﻿using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Runtime.CompilerServices;

namespace Vanara.PInvoke;

public static partial class Kernel32
{
	/// <summary>Disable</summary>
	public const uint PME_FAILFAST_ON_COMMIT_FAIL_DISABLE = 0x0;

	/// <summary>Enable</summary>
	public const uint PME_FAILFAST_ON_COMMIT_FAIL_ENABLE = 0x1;

	/// <summary>Value indicating that there are no thread local storage indexes to allocate.</summary>
	public const uint TLS_OUT_OF_INDEXES = 0xFFFFFFFF;

	/// <summary>The maximum processors.</summary>
	public static readonly uint MAXIMUM_PROCESSORS = Is64bitOS() ? 64U : 32U;

	/// <summary>
	/// An application-defined completion routine. Specify this address when calling the QueueUserAPC function. The PAPCFUNC type defines a
	/// pointer to this callback function.
	/// </summary>
	/// <param name="dwParam">The data passed to the function using the dwData parameter of the QueueUserAPC function.</param>
	[UnmanagedFunctionPointer(CallingConvention.StdCall)]
	public delegate void PAPCFUNC(IntPtr dwParam);

	/// <summary>Represents the type of information in the <c>SYSTEM_CPU_SET_INFORMATION</c> structure.</summary>
	// typedef enum _CPU_SET_INFORMATION_TYPE { CpuSetInformation} CPU_SET_INFORMATION_TYPE, *PCPU_SET_INFORMATION_TYPE; https://msdn.microsoft.com/en-us/library/windows/desktop/mt186423(v=vs.85).aspx
	[PInvokeData("Processthreadapi.h", MSDNShortId = "mt186423")]
	public enum CPU_SET_INFORMATION_TYPE
	{
		/// <summary>The structure contains CPU Set information.</summary>
		CpuSetInformation
	}

	/// <summary>
	/// The following process creation flags are used by the <c>CreateProcess</c>, <c>CreateProcessAsUser</c>,
	/// <c>CreateProcessWithLogonW</c>, and <c>CreateProcessWithTokenW</c> functions. They can be specified in any combination, except as noted.
	/// </summary>
	// https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx
	[PInvokeData("WinBase.h", MSDNShortId = "ms684863")]
	[Flags]
	public enum CREATE_PROCESS : uint
	{
		/// <summary>
		/// The child processes of a process associated with a job are not associated with the job. If the calling process is not associated
		/// with a job, this constant has no effect. If the calling process is associated with a job, the job must set the
		/// JOB_OBJECT_LIMIT_BREAKAWAY_OK limit.
		/// </summary>
		CREATE_BREAKAWAY_FROM_JOB = 0x01000000,

		/// <summary>
		/// The new process does not inherit the error mode of the calling process. Instead, the new process gets the default error mode.
		/// This feature is particularly useful for multithreaded shell applications that run with hard errors disabled.The default behavior
		/// is for the new process to inherit the error mode of the caller. Setting this flag changes that default behavior.
		/// </summary>
		CREATE_DEFAULT_ERROR_MODE = 0x04000000,

		/// <summary>
		/// The new process has a new console, instead of inheriting its parent's console (the default). For more information, see Creation
		/// of a Console. This flag cannot be used with DETACHED_PROCESS.
		/// </summary>
		CREATE_NEW_CONSOLE = 0x00000010,

		/// <summary>
		/// The new process is the root process of a new process group. The process group includes all processes that are descendants of this
		/// root process. The process identifier of the new process group is the same as the process identifier, which is returned in the
		/// lpProcessInformation parameter. Process groups are used by the GenerateConsoleCtrlEvent function to enable sending a CTRL+BREAK
		/// signal to a group of console processes.If this flag is specified, CTRL+C signals will be disabled for all processes within the
		/// new process group.This flag is ignored if specified with CREATE_NEW_CONSOLE.
		/// </summary>
		CREATE_NEW_PROCESS_GROUP = 0x00000200,

		/// <summary>
		/// The process is a console application that is being run without a console window. Therefore, the console handle for the
		/// application is not set.This flag is ignored if the application is not a console application, or if it is used with either
		/// CREATE_NEW_CONSOLE or DETACHED_PROCESS.
		/// </summary>
		CREATE_NO_WINDOW = 0x08000000,

		/// <summary>
		/// The process is to be run as a protected process. The system restricts access to protected processes and the threads of protected
		/// processes. For more information on how processes can interact with protected processes, see Process Security and Access Rights.To
		/// activate a protected process, the binary must have a special signature. This signature is provided by Microsoft but not currently
		/// available for non-Microsoft binaries. There are currently four protected processes: media foundation, audio engine, Windows error
		/// reporting, and system. Components that load into these binaries must also be signed. Multimedia companies can leverage the first
		/// two protected processes. For more information, see Overview of the Protected Media Path.Windows Server 2003 and Windows XP: This
		/// value is not supported.
		/// </summary>
		CREATE_PROTECTED_PROCESS = 0x00040000,

		/// <summary>
		/// Allows the caller to execute a child process that bypasses the process restrictions that would normally be applied automatically
		/// to the process.
		/// </summary>
		CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000,

		/// <summary>This flag allows secure processes, that run in the Virtualization-Based Security environment, to launch.</summary>
		CREATE_SECURE_PROCESS = 0x00400000,

		/// <summary>
		/// This flag is valid only when starting a 16-bit Windows-based application. If set, the new process runs in a private Virtual DOS
		/// Machine (VDM). By default, all 16-bit Windows-based applications run as threads in a single, shared VDM. The advantage of running
		/// separately is that a crash only terminates the single VDM; any other programs running in distinct VDMs continue to function
		/// normally. Also, 16-bit Windows-based applications that are run in separate VDMs have separate input queues. That means that if
		/// one application stops responding momentarily, applications in separate VDMs continue to receive input. The disadvantage of
		/// running separately is that it takes significantly more memory to do so. You should use this flag only if the user requests that
		/// 16-bit applications should run in their own VDM.
		/// </summary>
		CREATE_SEPARATE_WOW_VDM = 0x00000800,

		/// <summary>
		/// The flag is valid only when starting a 16-bit Windows-based application. If the DefaultSeparateVDM switch in the Windows section
		/// of WIN.INI is TRUE, this flag overrides the switch. The new process is run in the shared Virtual DOS Machine.
		/// </summary>
		CREATE_SHARED_WOW_VDM = 0x00001000,

		/// <summary>
		/// The primary thread of the new process is created in a suspended state, and does not run until the ResumeThread function is called.
		/// </summary>
		CREATE_SUSPENDED = 0x00000004,

		/// <summary>
		/// If this flag is set, the environment block pointed to by lpEnvironment uses Unicode characters. Otherwise, the environment block
		/// uses ANSI characters.
		/// </summary>
		CREATE_UNICODE_ENVIRONMENT = 0x00000400,

		/// <summary>
		/// The calling thread starts and debugs the new process. It can receive all related debug events using the WaitForDebugEvent function.
		/// </summary>
		DEBUG_ONLY_THIS_PROCESS = 0x00000002,

		/// <summary>
		/// The calling thread starts and debugs the new process and all child processes created by the new process. It can receive all
		/// related debug events using the WaitForDebugEvent function. A process that uses DEBUG_PROCESS becomes the root of a debugging
		/// chain. This continues until another process in the chain is created with DEBUG_PROCESS.If this flag is combined with
		/// DEBUG_ONLY_THIS_PROCESS, the caller debugs only the new process, not any child processes.
		/// </summary>
		DEBUG_PROCESS = 0x00000001,

		/// <summary>
		/// For console processes, the new process does not inherit its parent's console (the default). The new process can call the
		/// AllocConsole function at a later time to create a console. For more information, see Creation of a Console. This value cannot be
		/// used with CREATE_NEW_CONSOLE.
		/// </summary>
		DETACHED_PROCESS = 0x00000008,

		/// <summary>
		/// The process is created with extended startup information; the lpStartupInfo parameter specifies a STARTUPINFOEX structure.Windows
		/// Server 2003 and Windows XP: This value is not supported.
		/// </summary>
		EXTENDED_STARTUPINFO_PRESENT = 0x00080000,

		/// <summary>
		/// The process inherits its parent's affinity. If the parent process has threads in more than one processor group, the new process
		/// inherits the group-relative affinity of an arbitrary group in use by the parent.Windows Server 2008, Windows Vista, Windows
		/// Server 2003 and Windows XP: This value is not supported.
		/// </summary>
		INHERIT_PARENT_AFFINITY = 0x00010000,

		/// <summary>Process with no special scheduling needs.</summary>
		NORMAL_PRIORITY_CLASS = 0x00000020,

		/// <summary>
		/// Process whose threads run only when the system is idle and are preempted by the threads of any process running in a higher
		/// priority class. An example is a screen saver. The idle priority class is inherited by child processes.
		/// </summary>
		IDLE_PRIORITY_CLASS = 0x00000040,

		/// <summary>
		/// Process that performs time-critical tasks that must be executed immediately for it to run correctly. The threads of a
		/// high-priority class process preempt the threads of normal or idle priority class processes. An example is the Task List, which
		/// must respond quickly when called by the user, regardless of the load on the operating system. Use extreme care when using the
		/// high-priority class, because a high-priority class CPU-bound application can use nearly all available cycles.
		/// </summary>
		HIGH_PRIORITY_CLASS = 0x00000080,

		/// <summary>
		/// Process that has the highest possible priority. The threads of a real-time priority class process preempt the threads of all
		/// other processes, including operating system processes performing important tasks. For example, a real-time process that executes
		/// for more than a very brief interval can cause disk caches not to flush or cause the mouse to be unresponsive.
		/// </summary>
		REALTIME_PRIORITY_CLASS = 0x00000100,

		/// <summary>Process that has priority above IDLE_PRIORITY_CLASS but below NORMAL_PRIORITY_CLASS.</summary>
		BELOW_NORMAL_PRIORITY_CLASS = 0x00004000,

		/// <summary>Process that has priority above NORMAL_PRIORITY_CLASS but below HIGH_PRIORITY_CLASS.</summary>
		ABOVE_NORMAL_PRIORITY_CLASS = 0x00008000,

		/// <summary>Undocumented.</summary>
		CREATE_FORCEDOS = 0x00002000,

		/// <summary>Creates profiles for the user mode modeuls of the process.</summary>
		PROFILE_USER = 0x10000000,

		/// <summary>Undocumented.</summary>
		PROFILE_KERNEL = 0x20000000,

		/// <summary>Undocumented.</summary>
		PROFILE_SERVER = 0x40000000,

		/// <summary>Undocumented.</summary>
		CREATE_IGNORE_SYSTEM_DEFAULT = 0x80000000,

		/// <summary>Undocumented.</summary>
		INHERIT_CALLER_PRIORITY = 0x00020000,

		/// <summary>
		/// Begin background processing mode. The system lowers the resource scheduling priorities of the process (and its threads) so that
		/// it can perform background work without significantly affecting activity in the foreground.
		/// <para>
		/// This value can be specified only if hProcess is a handle to the current process. The function fails if the process is already in
		/// background processing mode.
		/// </para>
		/// <para>Windows Server 2003 and Windows XP: This value is not supported.</para>
		/// </summary>
		PROCESS_MODE_BACKGROUND_BEGIN = 0x00100000,

		/// <summary>
		/// End background processing mode. The system restores the resource scheduling priorities of the process (and its threads) as they
		/// were before the process entered background processing mode.
		/// <para>
		/// This value can be specified only if hProcess is a handle to the current process. The function fails if the process is not in
		/// background processing mode.
		/// </para>
		/// <para>Windows Server 2003 and Windows XP: This value is not supported.</para>
		/// </summary>
		PROCESS_MODE_BACKGROUND_END = 0x00200000,
	}

	/// <summary>
	/// Flags used by <see cref="CreateRemoteThread(HPROCESS, SECURITY_ATTRIBUTES, SizeT, IntPtr, IntPtr, CREATE_THREAD_FLAGS, out uint)"/>.
	/// </summary>
	[Flags]
	public enum CREATE_THREAD_FLAGS
	{
		/// <term>The thread runs immediately after creation.</term>
		RUN_IMMEDIATELY = 0,

		/// <term>The thread is created in a suspended state, and does not run until the ResumeThread function is called.</term>
		CREATE_SUSPENDED = 4,

		/// The dwStackSize parameter specifies the initial reserve size of the stack. If this flag is not specified, dwStackSize specifies
		/// the commit size.
		STACK_SIZE_PARAM_IS_A_RESERVATION = 0x00010000,
	}

	/// <summary>Flags that apply to the dynamic exception handling continuation target in TargetAddress in <see cref="PROCESS_DYNAMIC_EH_CONTINUATION_TARGET"/>.</summary>
	[PInvokeData("winnt.h", MSDNShortId = "NS:winnt._PROCESS_DYNAMIC_EH_CONTINUATION_TARGET")]
	[Flags]
	public enum DYNAMIC_EH_CONTINUATION_TARGET
	{
		/// <summary>
		/// Dynamic exception handling continuation target should be added. If this flag is not set, the target is removed. This is an input flag.
		/// </summary>
		DYNAMIC_EH_CONTINUATION_TARGET_ADD = 0x00000001,

		/// <summary>
		/// Dynamic exception handling continuation target has been successfully processed (either added or removed). This is an output flag
		/// used to report which targets were successfully processed when processing an array of multiple targets.
		/// </summary>
		DYNAMIC_EH_CONTINUATION_TARGET_PROCESSED = 0x00000002
	}

	/// <summary>Specifies the ways in which an architecture of code can run on a host operating system. More than one bit may be set.</summary>
	// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ne-processthreadsapi-machine_attributes typedef enum
	// _MACHINE_ATTRIBUTES { UserEnabled, KernelEnabled, Wow64Container } MACHINE_ATTRIBUTES;
	[PInvokeData("processthreadsapi.h", MSDNShortId = "NE:processthreadsapi._MACHINE_ATTRIBUTES")]
	public enum MACHINE_ATTRIBUTES
	{
		/// <summary>The specified architecture of code can run in user mode.</summary>
		UserEnabled,

		/// <summary>The specified architecture of code can run in kernel mode.</summary>
		KernelEnabled,

		/// <summary>
		/// The specified architecture of code runs by relying on WOW64's namespace <c>File System Redirector</c> and <c>Registry
		/// Redirector</c>. This bit will be set, for example, on x86 code running on a host operating system that is x64 or ARM64. When the
		/// compatibility layer does not use WOW64 style filesystem and registry namespaces, like x64 on ARM64 which runs on the root
		/// namespace of the OS, this bit will be reset.
		/// </summary>
		Wow64Container,
	}

	/// <summary>The memory priority for the thread or process.</summary>
	public enum MEMORY_PRIORITY
	{
		/// <summary>Lowest memory priority.</summary>
		MEMORY_PRIORITY_LOWEST = 0,

		/// <summary>Very low memory priority.</summary>
		MEMORY_PRIORITY_VERY_LOW = 1,

		/// <summary>Low memory priority.</summary>
		MEMORY_PRIORITY_LOW = 2,

		/// <summary>Medium memory priority.</summary>
		MEMORY_PRIORITY_MEDIUM = 3,

		/// <summary>Below normal memory priority.</summary>
		MEMORY_PRIORITY_BELOW_NORMAL = 4,

		/// <summary>Normal memory priority. This is the default priority for all threads and processes on the system.</summary>
		MEMORY_PRIORITY_NORMAL = 5,
	}

	/// <summary>The affinity update mode.</summary>
	public enum PROCESS_AFFINITY_MODE
	{
		/// <summary>Dynamic update of the process affinity by the system is disabled.</summary>
		PROCESS_AFFINITY_DISABLE_AUTO_UPDATE,

		/// <summary>Dynamic update of the process affinity by the system is enabled.</summary>
		PROCESS_AFFINITY_ENABLE_AUTO_UPDATE
	}

	/// <summary>
	/// Indicates a specific class of process information. Values from this enumeration are passed into the GetProcessInformation and
	/// SetProcessInformation functions to specify the type of process information passed in the void pointer argument of the function call.
	/// </summary>
	// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ne-processthreadsapi-process_information_class typedef enum
	// _PROCESS_INFORMATION_CLASS { ProcessMemoryPriority, ProcessMemoryExhaustionInfo, ProcessAppMemoryInfo, ProcessInPrivateInfo,
	// ProcessPowerThrottling, ProcessReservedValue1, ProcessTelemetryCoverageInfo, ProcessProtectionLevelInfo, ProcessLeapSecondInfo,
	// ProcessMachineTypeInfo, ProcessInformationClassMax } PROCESS_INFORMATION_CLASS;
	[PInvokeData("processthreadsapi.h", MSDNShortId = "NE:processthreadsapi._PROCESS_INFORMATION_CLASS")]
	public enum PROCESS_INFORMATION_CLASS
	{
		/// <summary>
		/// The process information is represented by a MEMORY_PRIORITY_INFORMATION structure. Allows applications to lower the default
		/// memory priority of threads that perform background operations or access files and data that are not expected to be accessed again soon.
		/// </summary>
		[CorrespondingType(typeof(MEMORY_PRIORITY_INFORMATION), CorrespondingAction.GetSet)]
		ProcessMemoryPriority,

		/// <summary>
		/// The process information is represented by a PROCESS_MEMORY_EXHAUSTION_INFO structure. Allows applications to configure a process
		/// to terminate if an allocation fails to commit memory.
		/// </summary>
		[CorrespondingType(typeof(PROCESS_MEMORY_EXHAUSTION_INFO), CorrespondingAction.Set)]
		ProcessMemoryExhaustionInfo,

		/// <summary>
		/// The process information is represented by a APP_MEMORY_INFORMATION structure. Allows applications to query the commit usage and
		/// the additional commit available to this process. Does not allow the caller to actually get a commit limit.
		/// </summary>
		[CorrespondingType(typeof(APP_MEMORY_INFORMATION), CorrespondingAction.Get)]
		ProcessAppMemoryInfo,

		/// <summary>
		/// If a process is set to <c>ProcessInPrivate</c> mode, and a trace session has set the EVENT_ENABLE_PROPERTY_EXCLUDE_INPRIVATE
		/// flag, then the trace session will drop all events from that process.
		/// </summary>
		ProcessInPrivateInfo,

		/// <summary>
		/// The process information is represented by a PROCESS_POWER_THROTTLING_STATE structure. Allows applications to configure how the
		/// system should throttle the target process’s activity when managing power.
		/// </summary>
		[CorrespondingType(typeof(PROCESS_POWER_THROTTLING_STATE), CorrespondingAction.GetSet)]
		ProcessPowerThrottling,

		/// <summary>Reserved.</summary>
		ProcessReservedValue1,

		/// <summary>Reserved.</summary>
		ProcessTelemetryCoverageInfo,

		/// <summary>The process information is represented by a PROCESS_PROTECTION_LEVEL_INFORMATION structure.</summary>
		[CorrespondingType(typeof(PROCESS_PROTECTION_LEVEL_INFORMATION), CorrespondingAction.Get)]
		ProcessProtectionLevelInfo,

		/// <summary>The process information is represented by a PROCESS_LEAP_SECOND_INFO structure.</summary>
		[CorrespondingType(typeof(PROCESS_LEAP_SECOND_INFO), CorrespondingAction.GetSet)]
		ProcessLeapSecondInfo,

		/// <summary>The process is represented by a PROCESS_MACHINE_INFORMATION structure.</summary>
		[CorrespondingType(typeof(PROCESS_MACHINE_INFORMATION), CorrespondingAction.Get)]
		ProcessMachineTypeInfo,
	}

	/// <summary>Flags for <see cref="PROCESS_LEAP_SECOND_INFO.Flags"/>.</summary>
	[PInvokeData("processthreadsapi.h")]
	[Flags]
	public enum PROCESS_LEAP_SECOND_INFO_FLAGS
	{
		/// <summary>
		/// This value changes the way positive leap seconds are handled by system. Specifically, it changes how the seconds field during a
		/// positive leap second is handled by the system. If this value is used, then the positive leap second will be shown (For example:
		/// 23:59:59 -&gt; 23:59:60 -&gt; 00:00:00. If this value is not used, then "sixty seconds" is disabled, and the 59th second
		/// preceding a positive leap second will be shown for 2 seconds with the milliseconds value ticking twice as slow. So 23:59:59 -&gt;
		/// 23:59:59.500 -&gt; 00:00:00, which takes 2 seconds in wall clock time. Disabling "sixty second" can help with legacy apps that do
		/// not support seeing the seconds value as 60 during the positive leap second. Such apps may crash or misbehave. Therefore, in these
		/// cases, we display the 59th second for twice as long during the positive leap second. Note that this setting is per-process, and
		/// does not persist if the process is restarted. Developers should test their app for compatibility with seeing the system return
		/// "60", and add a call to their app startup routines to either enable or disable "sixty seconds". "Sixty seconds" is disabled by
		/// default for each process. Obviously, this setting has no effect if leap seconds are disabled system-wide, because then the system
		/// will never even encounter a leap second.
		/// </summary>
		PROCESS_LEAP_SECOND_INFO_FLAG = 1
	}

	/// <summary>Represents the different memory exhaustion types.</summary>
	// typedef enum _PROCESS_MEMORY_EXHAUSTION_TYPE { PMETypeFailFastOnCommitFailure, PMETypeMax} PROCESS_MEMORY_EXHAUSTION_TYPE,
	// *PPROCESS_MEMORY_EXHAUSTION_TYPE;// https://msdn.microsoft.com/en-us/library/windows/desktop/mt767998(v=vs.85).aspx
	[PInvokeData("WinBase.h", MSDNShortId = "mt767998")]
	public enum PROCESS_MEMORY_EXHAUSTION_TYPE
	{
		/// <summary>
		/// Anytime memory management fails an allocation due to an inability to commit memory, it will cause the process to trigger a
		/// Windows Error Reporting report and then terminate immediately with <c>STATUS_COMMITMENT_LIMIT</c>. The failure cannot be caught
		/// and handled by the app.
		/// </summary>
		PMETypeFailFastOnCommitFailure,

		/// <summary>The maximum value for this enumeration. This value may change in a future version.</summary>
		PMETypeMax
	}

	/// <summary>Flags used by PROCESS_MITIGATION_ASLR_POLICY</summary>
	[Flags]
	public enum PROCESS_MITIGATION_ASLR_POLICY_FLAGS : uint
	{
		/// <summary>
		/// Thread stacks and other bottom-up allocations are subject to randomization by ASLR if this flag is set. This flag is read-only
		/// and cannot be modified after a process has been created.
		/// </summary>
		EnableBottomUpRandomization = 1 << 0,

		/// <summary>Images that have not been built with /DYNAMICBASE are forcibly relocated on load if this flag is set.</summary>
		EnableForceRelocateImages = 1 << 1,

		/// <summary>
		/// Bottom-up allocations are subject to higher degrees of entropy when randomized by ASLR if this flag is set. This flag only
		/// applies to 64-bit processes and is read-only.
		/// </summary>
		EnableHighEntropy = 1 << 2,

		/// <summary>
		/// Images that have not been built with /DYNAMICBASE and do not have relocation information will fail to load if this flag and
		/// <c>EnableForceRelocateImages</c> are set.
		/// </summary>
		DisallowStrippedImages = 1 << 3,
	}

	/// <summary>Flags used by PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY.</summary>
	[Flags]
	public enum PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY_FLAGS : uint
	{
		/// <summary>Set (0x1) to prevent the process from loading images that are not signed by Microsoft; otherwise leave unset (0x0).</summary>
		MicrosoftSignedOnly = 1 << 0,

		/// <summary>
		/// Set (0x1) to prevent the process from loading images that are not signed by the Windows Store; otherwise leave unset (0x0).
		/// </summary>
		StoreSignedOnly = 1 << 1,

		/// <summary>
		/// Set (0x1) to prevent the process from loading images that are not signed by Microsoft, the Windows Store and the Windows Hardware
		/// Quality Labs (WHQL); otherwise leave unset (0x0).
		/// </summary>
		MitigationOptIn = 1 << 2,

		/// <summary>Undocumented</summary>
		AuditMicrosoftSignedOnly = 1 << 3,

		/// <summary>Undocumented</summary>
		AuditStoreSignedOnly = 1 << 4,
	}

	/// <summary>Flags used by PROCESS_MITIGATION_CHILD_PROCESS_POLICY.</summary>
	[Flags]
	public enum PROCESS_MITIGATION_CHILD_PROCESS_POLICY_FLAGS : uint
	{
		/// <summary>If set, the process cannot create child processes.</summary>
		NoChildProcessCreation = 1 << 0,

		/// <summary>
		/// If set, causes audit events to be generated when child processes are created by the process. If both NoChildProcessCreation and
		/// AuditNoChildProcessCreation are set, NoChildProcessCreation takes precedence over audit setting.
		/// </summary>
		AuditNoChildProcessCreation = 1 << 1,

		/// <summary>
		/// Denies creation of child processes unless the child process is a secure process and if creation was previously blocked. It allows
		/// a process to spawn a child process on behalf of another process that cannot itself create child processes. See
		/// PROCESS_CREATION_CHILD_PROCESS_OVERRIDE in UpdateProcThreadAttribute.
		/// </summary>
		AllowSecureProcessCreation = 1 << 2,
	}

	/// <summary>Flags used by PROCESS_MITIGATION_CONTROL_FLOW_GUARD_POLICY</summary>
	[Flags]
	public enum PROCESS_MITIGATION_CONTROL_FLOW_GUARD_POLICY_FLAGS : uint
	{
		/// <summary>CFG is enabled for the process if this flag is set. This field cannot be changed via SetProcessMitigationPolicy.</summary>
		EnableControlFlowGuard = 1 << 0,

		/// <summary>
		/// If TRUE, exported functions will be treated as invalid indirect call targets by default. Exported functions only become valid
		/// indirect call targets if they are dynamically resolved via GetProcAddress. This field cannot be changed via <c>SetProcessMitigationPolicy</c>.
		/// </summary>
		EnableExportSuppression = 1 << 1,

		/// <summary>
		/// If TRUE, all DLLs that are loaded must enable CFG. If a DLL does not enable CFG then the image will fail to load. This policy can
		/// be enabled after a process has started by calling <c>SetProcessMitigationPolicy</c>. It cannot be disabled once enabled.
		/// </summary>
		StrictMode = 1 << 2,
	}

	/// <summary>Flags used by PROCESS_MITIGATION_DEP_POLICY</summary>
	[Flags]
	public enum PROCESS_MITIGATION_DEP_POLICY_FLAGS : uint
	{
		/// <summary>DEP is enabled for the process if this flag is set.</summary>
		Enable = 1 << 0,

		/// <summary>ATL thunk emulation is disabled for the process if this flag is set.</summary>
		DisableAtlThunkEmulation = 1 << 1,
	}

	/// <summary>Flags used by PROCESS_MITIGATION_DYNAMIC_CODE_POLICY</summary>
	[Flags]
	public enum PROCESS_MITIGATION_DYNAMIC_CODE_POLICY_FLAGS : uint
	{
		/// <summary>
		/// Set (0x1) to prevent the process from generating dynamic code or modifying existing executable code; otherwise leave unset (0x0).
		/// </summary>
		ProhibitDynamicCode = 1 << 0,

		/// <summary>
		/// Set (0x1) to allow threads to opt out of the restrictions on dynamic code generation by calling the <c>SetThreadInformation</c>
		/// function with the ThreadInformation parameter set to <c>ThreadDynamicCodePolicy</c>; otherwise leave unset (0x0). You should not
		/// use the <c>AllowThreadOptOut</c> and <c>ThreadDynamicCodePolicy</c> settings together to provide strong security. These settings
		/// are only intended to enable applications to adapt their code more easily for full dynamic code restrictions.
		/// </summary>
		AllowThreadOptOut = 1 << 1,

		/// <summary>
		/// Set (0x1) to allow non-AppContainer processes to modify all of the dynamic code settings for the calling process, including
		/// relaxing dynamic code restrictions after they have been set.
		/// </summary>
		AllowRemoteDowngrade = 1 << 2,

		/// <summary>Undocumented</summary>
		AuditProhibitDynamicCode = 1 << 3,
	}

	/// <summary>Flags used by PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY</summary>
	[Flags]
	public enum PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY_FLAGS : uint
	{
		/// <summary>Prevents legacy extension point DLLs from being loaded into the process.</summary>
		DisableExtensionPoints = 1 << 0,
	}

	/// <summary>Flags used by PROCESS_MITIGATION_FONT_DISABLE_POLICY.</summary>
	[Flags]
	public enum PROCESS_MITIGATION_FONT_DISABLE_POLICY_FLAGS : uint
	{
		/// <summary>Set (0x1) to prevent the process from loading non-system fonts; otherwise leave unset (0x0).</summary>
		DisableNonSystemFonts = 1 << 0,

		/// <summary>
		/// Set (0x1) to indicate that an Event Tracing for Windows (ETW) event should be logged when the process attempts to load a
		/// non-system font; leave unset (0x0) to indicate that an ETW event should not be logged.
		/// </summary>
		AuditNonSystemFontLoading = 1 << 1,
	}

	/// <summary>Flags used by PROCESS_MITIGATION_IMAGE_LOAD_POLICY.</summary>
	[Flags]
	public enum PROCESS_MITIGATION_IMAGE_LOAD_POLICY_FLAGS : uint
	{
		/// <summary>
		/// Set (0x1) to prevent the process from loading images from a remote device, such as a UNC share; otherwise leave unset (0x0).
		/// </summary>
		NoRemoteImages = 1 << 0,

		/// <summary>
		/// Set (0x1) to prevent the process from loading images that have a Low mandatory label, as written by low IL; otherwise leave unset (0x0).
		/// </summary>
		NoLowMandatoryLabelImages = 1 << 1,

		/// <summary>
		/// Set (0x1) to search for images to load in the System32 subfolder of the folder in which Windows is installed first, then in the
		/// application directory in the standard DLL search order; otherwise leave unset (0x0).
		/// </summary>
		PreferSystem32Images = 1 << 2,

		/// <summary>Undocumented.</summary>
		AuditNoRemoteImages = 1 << 3,

		/// <summary>Undocumented.</summary>
		AuditNoLowMandatoryLabelImages = 1 << 4,
	}

	/// <summary>Flags used by PROCESS_MITIGATION_PAYLOAD_RESTRICTION_POLICY.</summary>
	[Flags]
	public enum PROCESS_MITIGATION_PAYLOAD_RESTRICTION_POLICY_FLAGS : uint
	{
		/// <summary>If set this enables the Export Address Filter mitigation in enforcement mode for the process.</summary>
		EnableExportAddressFilter = 1 << 0,

		/// <summary>If set this enables the Export Address Filter mitigation in audit mode for the process.</summary>
		AuditExportAddressFilter = 1 << 1,

		/// <summary>If set this enables the Export Address Filter Plus mitigation in enforcement mode for the process.</summary>
		EnableExportAddressFilterPlus = 1 << 2,

		/// <summary>If set this enables the Export Address Filter mitigation in audit mode for the process.</summary>
		AuditExportAddressFilterPlus = 1 << 3,

		/// <summary>If set this enables the Import Address Filter mitigation in enforcement mode for the process.</summary>
		EnableImportAddressFilter = 1 << 4,

		/// <summary>If set this enables the Import Address Filter mitigation in enforcement mode for the process.</summary>
		AuditImportAddressFilter = 1 << 5,

		/// <summary>
		/// If set this enables the stack pivot anti-ROP (Return-oriented-programming) mitigation in enforcement mode for the process.
		/// </summary>
		EnableRopStackPivot = 1 << 6,

		/// <summary>If set this enables the stack pivot anti-ROP (Return-oriented-programming) mitigation in audit mode for the process.</summary>
		AuditRopStackPivot = 1 << 7,

		/// <summary>
		/// If set this enables the caller check anti-ROP (Return-oriented-programming) mitigation in enforcement mode for the process.
		/// Applies to 32-bit processes only.
		/// </summary>
		EnableRopCallerCheck = 1 << 8,

		/// <summary>
		/// If set this enables the caller check anti-ROP (Return-oriented-programming) mitigation in audit mode for the process. Applies to
		/// 32-bit processes only.
		/// </summary>
		AuditRopCallerCheck = 1 << 9,

		/// <summary>
		/// If set this enables the simulated execution anti-ROP (Return-oriented-programming) mitigation in enforcement mode for the
		/// process. Applies to 32-bit processes only.
		/// </summary>
		EnableRopSimExec = 1 << 10,

		/// <summary>
		/// If set this enables the simulated execution anti-ROP (Return-oriented-programming) mitigation in audit mode for the process.
		/// Applies to 32-bit processes only.
		/// </summary>
		AuditRopSimExec = 1 << 11,
	}

	/// <summary>Represents the different process mitigation policies.</summary>
	[PInvokeData("winnt.h")]
	public enum PROCESS_MITIGATION_POLICY
	{
		/// <summary>The data execution prevention (DEP) policy of the process.</summary>
		[CorrespondingType(typeof(PROCESS_MITIGATION_DEP_POLICY))]
		ProcessDEPPolicy,

		/// <summary>The Address Space Layout Randomization (ASLR) policy of the process.</summary>
		[CorrespondingType(typeof(PROCESS_MITIGATION_ASLR_POLICY))]
		ProcessASLRPolicy,

		/// <summary>The policy that turns off the ability of the process to generate dynamic code or modify existing executable code.</summary>
		[CorrespondingType(typeof(PROCESS_MITIGATION_DYNAMIC_CODE_POLICY))]
		ProcessDynamicCodePolicy,

		/// <summary>
		/// The process will receive a fatal error if it manipulates an invalid handle. Useful for preventing downstream problems in a
		/// process due to handle misuse.
		/// </summary>
		[CorrespondingType(typeof(PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY))]
		ProcessStrictHandleCheckPolicy,

		/// <summary>Disables the ability to use NTUser/GDI functions at the lowest layer.</summary>
		[CorrespondingType(typeof(PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY))]
		ProcessSystemCallDisablePolicy,

		/// <summary>
		/// Returns the mask of valid bits for all the mitigation options on the system. An application can set many mitigation options
		/// without querying the operating system for mitigation options by combining bitwise with the mask to exclude all non-supported bits
		/// at once.
		/// </summary>
		[CorrespondingType(typeof(ulong[]))]
		ProcessMitigationOptionsMask,

		/// <summary>
		/// The policy that prevents some built-in third party extension points from being turned on, which prevents legacy extension point
		/// DLLs from being loaded into the process.
		/// </summary>
		[CorrespondingType(typeof(PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY))]
		ProcessExtensionPointDisablePolicy,

		/// <summary>The Control Flow Guard (CFG) policy of the process.</summary>
		[CorrespondingType(typeof(PROCESS_MITIGATION_CONTROL_FLOW_GUARD_POLICY))]
		ProcessControlFlowGuardPolicy,

		/// <summary>
		/// The policy of a process that can restrict image loading to those images that are either signed by Microsoft, by the Windows
		/// Store, or by Microsoft, the Windows Store and the Windows Hardware Quality Labs (WHQL).
		/// </summary>
		[CorrespondingType(typeof(PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY))]
		ProcessSignaturePolicy,

		/// <summary>The policy that turns off the ability of the process to load non-system fonts.</summary>
		[CorrespondingType(typeof(PROCESS_MITIGATION_FONT_DISABLE_POLICY))]
		ProcessFontDisablePolicy,

		/// <summary>
		/// The policy that turns off the ability of the process to load images from some locations, such a remote devices or files that have
		/// the low mandatory label.
		/// </summary>
		[CorrespondingType(typeof(PROCESS_MITIGATION_IMAGE_LOAD_POLICY))]
		ProcessImageLoadPolicy,
	}

	/// <summary>Flags used by PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY</summary>
	[Flags]
	public enum PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY_FLAGS : uint
	{
		/// <summary>
		/// When set to 1, an exception is raised if an invalid handle to a kernel object is used. Except as noted in the Remarks section,
		/// once exceptions for invalid handles are enabled for a process, they cannot be disabled.
		/// </summary>
		RaiseExceptionOnInvalidHandleReference = 1 << 0,

		/// <summary>When set to 1, exceptions for invalid kernel handles are permanently enabled.</summary>
		HandleExceptionsPermanentlyEnabled = 1 << 1,
	}

	/// <summary>Flags used by PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY</summary>
	[Flags]
	public enum PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY_FLAGS : uint
	{
		/// <summary>When set to 1, the process is not permitted to perform GUI system calls.</summary>
		DisallowWin32kSystemCalls = 1 << 0,

		/// <summary>Undocumented.</summary>
		AuditDisallowWin32kSystemCalls = 1 << 1,
	}

	/// <summary>Enables the caller to take control of the power throttling mechanism.</summary>
	[PInvokeData("processthreadsapi.h", MSDNShortId = "394B6509-849C-4B4C-9A46-AF5011A03585")]
	[Flags]
	public enum PROCESS_POWER_THROTTLING_MASK
	{
		/// <summary>Manages the execution speed of the process.</summary>
		PROCESS_POWER_THROTTLING_EXECUTION_SPEED = 1
	}

	/// <summary>
	/// <para>
	/// The Microsoft Windows security model enables you to control access to process objects. For more information about security, see
	/// Access-Control Model.
	/// </para>
	/// <para>
	/// When a user logs in, the system collects a set of data that uniquely identifies the user during the authentication process, and
	/// stores it in an access token. This access token describes the security context of all processes associated with the user. The
	/// security context of a process is the set of credentials given to the process or the user account that created the process.
	/// </para>
	/// <para>
	/// You can use a token to specify the current security context for a process using the <c>CreateProcessWithTokenW</c> function. You can
	/// specify a security descriptor for a process when you call the <c>CreateProcess</c>, <c>CreateProcessAsUser</c>, or
	/// <c>CreateProcessWithLogonW</c> function. If you specify <c>NULL</c>, the process gets a default security descriptor. The ACLs in the
	/// default security descriptor for a process come from the primary or impersonation token of the creator.
	/// </para>
	/// <para>
	/// To retrieve a process's security descriptor, call the <c>GetSecurityInfo</c> function. To change a process's security descriptor,
	/// call the <c>SetSecurityInfo</c> function.
	/// </para>
	/// <para>
	/// The valid access rights for process objects include the standard access rights and some process-specific access rights. The following
	/// table lists the standard access rights used by all objects.
	/// </para>
	/// <list type="table">
	/// <listheader>
	/// <term>Value</term>
	/// <term>Meaning</term>
	/// </listheader>
	/// <item>
	/// <term>DELETE (0x00010000L)</term>
	/// <term>Required to delete the object.</term>
	/// </item>
	/// <item>
	/// <term>READ_CONTROL (0x00020000L)</term>
	/// <term>
	/// Required to read information in the security descriptor for the object, not including the information in the SACL. To read or write
	/// the SACL, you must request the ACCESS_SYSTEM_SECURITY access right. For more information, see SACL Access Right.
	/// </term>
	/// </item>
	/// <item>
	/// <term>SYNCHRONIZE (0x00100000L)</term>
	/// <term>The right to use the object for synchronization. This enables a thread to wait until the object is in the signaled state.</term>
	/// </item>
	/// <item>
	/// <term>WRITE_DAC (0x00040000L)</term>
	/// <term>Required to modify the DACL in the security descriptor for the object.</term>
	/// </item>
	/// <item>
	/// <term>WRITE_OWNER (0x00080000L)</term>
	/// <term>Required to change the owner in the security descriptor for the object.</term>
	/// </item>
	/// </list>
	/// <para>The following table lists the process-specific access rights.</para>
	/// <list type="table">
	/// <listheader>
	/// <term>Value</term>
	/// <term>Meaning</term>
	/// </listheader>
	/// <item>
	/// <term>PROCESS_ALL_ACCESS</term>
	/// <term>
	/// All possible access rights for a process object.Windows Server 2003 and Windows XP: The size of the PROCESS_ALL_ACCESS flag increased
	/// on Windows Server 2008 and Windows Vista. If an application compiled for Windows Server 2008 and Windows Vista is run on Windows
	/// Server 2003 or Windows XP, the PROCESS_ALL_ACCESS flag is too large and the function specifying this flag fails with
	/// ERROR_ACCESS_DENIED. To avoid this problem, specify the minimum set of access rights required for the operation. If
	/// PROCESS_ALL_ACCESS must be used, set _WIN32_WINNT to the minimum operating system targeted by your application (for example, ). For
	/// more information, see Using the Windows Headers.
	/// </term>
	/// </item>
	/// <item>
	/// <term>PROCESS_CREATE_PROCESS (0x0080)</term>
	/// <term>Required to create a process.</term>
	/// </item>
	/// <item>
	/// <term>PROCESS_CREATE_THREAD (0x0002)</term>
	/// <term>Required to create a thread.</term>
	/// </item>
	/// <item>
	/// <term>PROCESS_DUP_HANDLE (0x0040)</term>
	/// <term>Required to duplicate a handle using DuplicateHandle.</term>
	/// </item>
	/// <item>
	/// <term>PROCESS_QUERY_INFORMATION (0x0400)</term>
	/// <term>Required to retrieve certain information about a process, such as its token, exit code, and priority class (see OpenProcessToken).</term>
	/// </item>
	/// <item>
	/// <term>PROCESS_QUERY_LIMITED_INFORMATION (0x1000)</term>
	/// <term>
	/// Required to retrieve certain information about a process (see GetExitCodeProcess, GetPriorityClass, IsProcessInJob,
	/// QueryFullProcessImageName). A handle that has the PROCESS_QUERY_INFORMATION access right is automatically granted
	/// PROCESS_QUERY_LIMITED_INFORMATION.Windows Server 2003 and Windows XP: This access right is not supported.
	/// </term>
	/// </item>
	/// <item>
	/// <term>PROCESS_SET_INFORMATION (0x0200)</term>
	/// <term>Required to set certain information about a process, such as its priority class (see SetPriorityClass).</term>
	/// </item>
	/// <item>
	/// <term>PROCESS_SET_QUOTA (0x0100)</term>
	/// <term>Required to set memory limits using SetProcessWorkingSetSize.</term>
	/// </item>
	/// <item>
	/// <term>PROCESS_SUSPEND_RESUME (0x0800)</term>
	/// <term>Required to suspend or resume a process.</term>
	/// </item>
	/// <item>
	/// <term>PROCESS_TERMINATE (0x0001)</term>
	/// <term>Required to terminate a process using TerminateProcess.</term>
	/// </item>
	/// <item>
	/// <term>PROCESS_VM_OPERATION (0x0008)</term>
	/// <term>Required to perform an operation on the address space of a process (see VirtualProtectEx and WriteProcessMemory).</term>
	/// </item>
	/// <item>
	/// <term>PROCESS_VM_READ (0x0010)</term>
	/// <term>Required to read memory in a process using ReadProcessMemory.</term>
	/// </item>
	/// <item>
	/// <term>PROCESS_VM_WRITE (0x0020)</term>
	/// <term>Required to write to memory in a process using WriteProcessMemory.</term>
	/// </item>
	/// <item>
	/// <term>SYNCHRONIZE (0x00100000L)</term>
	/// <term>Required to wait for the process to terminate using the wait functions.</term>
	/// </item>
	/// </list>
	/// <para>
	/// To open a handle to another process and obtain full access rights, you must enable the <c>SeDebugPrivilege</c> privilege. For more
	/// information, see Changing Privileges in a Token.
	/// </para>
	/// <para>
	/// The handle returned by the <c>CreateProcess</c> function has <c>PROCESS_ALL_ACCESS</c> access to the process object. When you call
	/// the <c>OpenProcess</c> function, the system checks the requested access rights against the DACL in the process's security descriptor.
	/// When you call the <c>GetCurrentProcess</c> function, the system returns a pseudohandle with the maximum access that the DACL allows
	/// to the caller.
	/// </para>
	/// <para>
	/// You can request the <c>ACCESS_SYSTEM_SECURITY</c> access right to a process object if you want to read or write the object's SACL.
	/// For more information, see Access-Control Lists (ACLs) and SACL Access Right.
	/// </para>
	/// </summary>
	// https://docs.microsoft.com/en-us/windows/win32/procthread/process-security-and-access-rights
	[PInvokeData("ntpsapi.h", MSDNShortId = "508a17c4-88cd-431a-a102-00180a7f7ab5")]
	[Flags]
	public enum ProcessAccess : uint
	{
		/// <summary>Required to terminate a process using TerminateProcess.</summary>
		PROCESS_TERMINATE = 0x0001,

		/// <summary>Required to create a thread.</summary>
		PROCESS_CREATE_THREAD = 0x0002,

		/// <summary/>
		PROCESS_SET_SESSIONID = 0x0004,

		/// <summary>Required to perform an operation on the address space of a process (see VirtualProtectEx and WriteProcessMemory).</summary>
		PROCESS_VM_OPERATION = 0x0008,

		/// <summary>Required to read memory in a process using ReadProcessMemory.</summary>
		PROCESS_VM_READ = 0x0010,

		/// <summary>Required to write to memory in a process using WriteProcessMemory.</summary>
		PROCESS_VM_WRITE = 0x0020,

		/// <summary>Required to duplicate a handle using DuplicateHandle.</summary>
		PROCESS_DUP_HANDLE = 0x0040,

		/// <summary>Required to create a process.</summary>
		PROCESS_CREATE_PROCESS = 0x0080,

		/// <summary>Required to set memory limits using SetProcessWorkingSetSize.</summary>
		PROCESS_SET_QUOTA = 0x0100,

		/// <summary>Required to set certain information about a process, such as its priority class (see SetPriorityClass).</summary>
		PROCESS_SET_INFORMATION = 0x0200,

		/// <summary>Required to retrieve certain information about a process, such as its token, exit code, and priority class (see OpenProcessToken).</summary>
		PROCESS_QUERY_INFORMATION = 0x0400,

		/// <summary>Required to suspend or resume a process.</summary>
		PROCESS_SUSPEND_RESUME = 0x0800,

		/// <summary>
		/// Required to retrieve certain information about a process (see GetExitCodeProcess, GetPriorityClass, IsProcessInJob,
		/// QueryFullProcessImageName). A handle that has the PROCESS_QUERY_INFORMATION access right is automatically granted
		/// PROCESS_QUERY_LIMITED_INFORMATION.Windows Server 2003 and Windows XP: This access right is not supported.
		/// </summary>
		PROCESS_QUERY_LIMITED_INFORMATION = 0x1000,

		/// <summary/>
		PROCESS_SET_LIMITED_INFORMATION = 0x2000,

		/// <summary>
		/// All possible access rights for a process object.Windows Server 2003 and Windows XP: The size of the PROCESS_ALL_ACCESS flag
		/// increased on Windows Server 2008 and Windows Vista. If an application compiled for Windows Server 2008 and Windows Vista is run
		/// on Windows Server 2003 or Windows XP, the PROCESS_ALL_ACCESS flag is too large and the function specifying this flag fails with
		/// ERROR_ACCESS_DENIED. To avoid this problem, specify the minimum set of access rights required for the operation. If
		/// PROCESS_ALL_ACCESS must be used, set _WIN32_WINNT to the minimum operating system targeted by your application (for example, ).
		/// For more information, see Using the Windows Headers.
		/// </summary>
		PROCESS_ALL_ACCESS = ACCESS_MASK.STANDARD_RIGHTS_REQUIRED | ACCESS_MASK.SYNCHRONIZE | 0xFFFF,
	}

	/// <summary>The processor feature to be tested.</summary>
	[PInvokeData("winnt.h", MSDNShortId = "ms724482")]
	public enum PROCESSOR_FEATURE
	{
		/// <summary>The alpha byte instructions are available.</summary>
		PF_ALPHA_BYTE_INSTRUCTIONS = 5,

		/// <summary>The 64-bit load/store atomic instructions are available.</summary>
		PF_ARM_64BIT_LOADSTORE_ATOMIC = 25,

		/// <summary>The divide instructions are available.</summary>
		PF_ARM_DIVIDE_INSTRUCTION_AVAILABLE = 24,

		/// <summary>The external cache is available.</summary>
		PF_ARM_EXTERNAL_CACHE_AVAILABLE = 26,

		/// <summary>The floating-point multiply-accumulate instruction is available.</summary>
		PF_ARM_FMAC_INSTRUCTIONS_AVAILABLE = 27,

		/// <summary>The neon instructions are available.</summary>
		PF_ARM_NEON_INSTRUCTIONS_AVAILABLE = 19,

		/// <summary>The v8 CRC32 instructions are available.</summary>
		PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE = 31,

		/// <summary>The v8 Crypto instructions are available.</summary>
		PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE = 30,

		/// <summary>The v8 instructions are available.</summary>
		PF_ARM_V8_INSTRUCTIONS_AVAILABLE = 29,

		/// <summary>The VFP/Neon: 32 x 64bit register bank is present. This flag has the same meaning as PF_ARM_VFP_EXTENDED_REGISTERS.</summary>
		PF_ARM_VFP_32_REGISTERS_AVAILABLE = 18,

		/// <summary>The 3D-Now instruction set is available.</summary>
		PF_3DNOW_INSTRUCTIONS_AVAILABLE = 7,

		/// <summary>The processor channels are enabled.</summary>
		PF_CHANNELS_ENABLED = 16,

		/// <summary>The atomic compare and exchange operation (cmpxchg) is available.</summary>
		PF_COMPARE_EXCHANGE_DOUBLE = 2,

		/// <summary>
		/// The atomic compare and exchange 128-bit operation (cmpxchg16b) is available.
		/// <para>Windows Server 2003 and Windows XP/2000: This feature is not supported.</para>
		/// </summary>
		PF_COMPARE_EXCHANGE128 = 14,

		/// <summary>
		/// The atomic compare 64 and exchange 128-bit operation (cmp8xchg16) is available.
		/// <para>Windows Server 2003 and Windows XP/2000: This feature is not supported.</para>
		/// </summary>
		PF_COMPARE64_EXCHANGE128 = 15,

		/// <summary>_fastfail() is available.</summary>
		PF_FASTFAIL_AVAILABLE = 23,

		/// <summary>
		/// Floating-point operations are emulated using a software emulator.
		/// <para>This function returns a nonzero value if floating-point operations are emulated; otherwise, it returns zero.</para>
		/// </summary>
		PF_FLOATING_POINT_EMULATED = 1,

		/// <summary>On a Pentium, a floating-point precision error can occur in rare circumstances.</summary>
		PF_FLOATING_POINT_PRECISION_ERRATA = 0,

		/// <summary>The MMX instruction set is available.</summary>
		PF_MMX_INSTRUCTIONS_AVAILABLE = 3,

		/// <summary>
		/// Data execution prevention is enabled.
		/// <para>Windows XP/2000: This feature is not supported until Windows XP with SP2 and Windows Server 2003 with SP1.</para>
		/// </summary>
		PF_NX_ENABLED = 12,

		/// <summary>
		/// The processor is PAE-enabled. For more information, see Physical Address Extension.
		/// <para>All x64 processors always return a nonzero value for this feature.</para>
		/// </summary>
		PF_PAE_ENABLED = 9,

		/// <summary>The PPC movemem 64 bit is ok.</summary>
		PF_PPC_MOVEMEM_64BIT_OK = 4,

		/// <summary>The pf rdrand instruction available</summary>
		PF_RDRAND_INSTRUCTION_AVAILABLE = 28,

		/// <summary>The RDTSC instruction is available.</summary>
		PF_RDTSC_INSTRUCTION_AVAILABLE = 8,

		/// <summary>The pf RDTSCP instruction available</summary>
		PF_RDTSCP_INSTRUCTION_AVAILABLE = 32,

		/// <summary>RDFSBASE, RDGSBASE, WRFSBASE, and WRGSBASE instructions are available.</summary>
		PF_RDWRFSGSBASE_AVAILABLE = 22,

		/// <summary>Second Level Address Translation is supported by the hardware.</summary>
		PF_SECOND_LEVEL_ADDRESS_TRANSLATION = 20,

		/// <summary>The pf sse daz mode available</summary>
		PF_SSE_DAZ_MODE_AVAILABLE = 11,

		/// <summary>
		/// The SSE3 instruction set is available.
		/// <para>Windows Server 2003 and Windows XP/2000: This feature is not supported.</para>
		/// </summary>
		PF_SSE3_INSTRUCTIONS_AVAILABLE = 13,

		/// <summary>Virtualization is enabled in the firmware.</summary>
		PF_VIRT_FIRMWARE_ENABLED = 21,

		/// <summary>The SSE instruction set is available.</summary>
		PF_XMMI_INSTRUCTIONS_AVAILABLE = 6,

		/// <summary>
		/// The SSE2 instruction set is available.
		/// <para>Windows 2000: This feature is not supported.</para>
		/// </summary>
		PF_XMMI64_INSTRUCTIONS_AVAILABLE = 10,

		/// <summary>
		/// The processor implements the XSAVE and XRSTOR instructions.
		/// <para>
		/// Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP/2000: This feature is not supported until Windows 7 and
		/// Windows Server 2008 R2.
		/// </para>
		/// </summary>
		PF_XSAVE_ENABLED = 17,
	}

	/// <summary>Process protection level.</summary>
	public enum PROTECTION_LEVEL : uint
	{
		/// <summary>For internal use only.</summary>
		PROTECTION_LEVEL_WINTCB_LIGHT = 0x00000000,

		/// <summary>For internal use only.</summary>
		PROTECTION_LEVEL_WINDOWS = 0x00000001,

		/// <summary>For internal use only.</summary>
		PROTECTION_LEVEL_WINDOWS_LIGHT = 0x00000002,

		/// <summary>For internal use only.</summary>
		PROTECTION_LEVEL_ANTIMALWARE_LIGHT = 0x00000003,

		/// <summary>For internal use only.</summary>
		PROTECTION_LEVEL_LSA_LIGHT = 0x00000004,

		/// <summary>Not implemented.</summary>
		PROTECTION_LEVEL_WINTCB = 0x00000005,

		/// <summary>Not implemented.</summary>
		PROTECTION_LEVEL_CODEGEN_LIGHT = 0x00000006,

		/// <summary>Not implemented.</summary>
		PROTECTION_LEVEL_AUTHENTICODE = 0x00000007,

		/// <summary>The process is a third party app that is using process protection.</summary>
		PROTECTION_LEVEL_PPL_APP = 0x00000008,

		/// <summary>The protection level same</summary>
		PROTECTION_LEVEL_SAME = 0xFFFFFFFF,

		/// <summary>The process is not protected.</summary>
		PROTECTION_LEVEL_NONE = 0xFFFFFFFE,
	}

	/// <summary>Value retrieved by the <see cref="GetProcessShutdownParameters"/> function.</summary>
	public enum SHUTDOWN
	{
		/// <summary>
		/// If this process takes longer than the specified timeout to shut down, do not display a retry dialog box for the user. Instead,
		/// just cause the process to directly exit.
		/// </summary>
		SHUTDOWN_NORETRY = 1
	}

	/// <summary>Flags used in the <see cref="STARTUPINFO.dwFlags"/> field.</summary>
	[PInvokeData("WinBase.h")]
	[Flags]
	public enum STARTF
	{
		/// <summary>
		/// Indicates that the cursor is in feedback mode for two seconds after CreateProcess is called. The Working in Background cursor is
		/// displayed (see the Pointers tab in the Mouse control panel utility). If during those two seconds the process makes the first GUI
		/// call, the system gives five more seconds to the process. If during those five seconds the process shows a window, the system
		/// gives five more seconds to the process to finish drawing the window.The system turns the feedback cursor off after the first call
		/// to GetMessage, regardless of whether the process is drawing.
		/// </summary>
		STARTF_FORCEONFEEDBACK = 0x00000040,

		/// <summary>Indicates that the feedback cursor is forced off while the process is starting. The Normal Select cursor is displayed.</summary>
		STARTF_FORCEOFFFEEDBACK = 0x00000080,

		/// <summary>
		/// Indicates that any windows created by the process cannot be pinned on the taskbar.This flag must be combined with STARTF_TITLEISAPPID.
		/// </summary>
		STARTF_PREVENTPINNING = 0x00002000,

		/// <summary>
		/// Indicates that the process should be run in full-screen mode, rather than in windowed mode. This flag is only valid for console
		/// applications running on an x86 computer.
		/// </summary>
		STARTF_RUNFULLSCREEN = 0x00000020,

		/// <summary>
		/// The lpTitle member contains an AppUserModelID. This identifier controls how the taskbar and Start menu present the application,
		/// and enables it to be associated with the correct shortcuts and Jump Lists. Generally, applications will use the
		/// SetCurrentProcessExplicitAppUserModelID and GetCurrentProcessExplicitAppUserModelID functions instead of setting this flag. For
		/// more information, see Application User Model IDs.If STARTF_PREVENTPINNING is used, application windows cannot be pinned on the
		/// taskbar. The use of any AppUserModelID-related window properties by the application overrides this setting for that window
		/// only.This flag cannot be used with STARTF_TITLEISLINKNAME.
		/// </summary>
		STARTF_TITLEISAPPID = 0x00001000,

		/// <summary>
		/// The lpTitle member contains the path of the shortcut file (.lnk) that the user invoked to start this process. This is typically
		/// set by the shell when a .lnk file pointing to the launched application is invoked. Most applications will not need to set this
		/// value.This flag cannot be used with STARTF_TITLEISAPPID.
		/// </summary>
		STARTF_TITLEISLINKNAME = 0x00000800,

		/// <summary>The command line came from an untrusted source. For more information, see Remarks.</summary>
		STARTF_UNTRUSTEDSOURCE = 0x00008000,

		/// <summary>The dwXCountChars and dwYCountChars members contain additional information.</summary>
		STARTF_USECOUNTCHARS = 0x00000008,

		/// <summary>The dwFillAttribute member contains additional information.</summary>
		STARTF_USEFILLATTRIBUTE = 0x00000010,

		/// <summary>The hStdInput member contains additional information. This flag cannot be used with STARTF_USESTDHANDLES.</summary>
		STARTF_USEHOTKEY = 0x00000200,

		/// <summary>The dwX and dwY members contain additional information.</summary>
		STARTF_USEPOSITION = 0x00000004,

		/// <summary>The wShowWindow member contains additional information.</summary>
		STARTF_USESHOWWINDOW = 0x00000001,

		/// <summary>The dwXSize and dwYSize members contain additional information.</summary>
		STARTF_USESIZE = 0x00000002,

		/// <summary>
		/// The hStdInput, hStdOutput, and hStdError members contain additional information. If this flag is specified when calling one of
		/// the process creation functions, the handles must be inheritable and the function's bInheritHandles parameter must be set to TRUE.
		/// For more information, see Handle Inheritance.If this flag is specified when calling the GetStartupInfo function, these members
		/// are either the handle value specified during process creation or INVALID_HANDLE_VALUE.Handles must be closed with CloseHandle
		/// when they are no longer needed.This flag cannot be used with STARTF_USEHOTKEY.
		/// </summary>
		STARTF_USESTDHANDLES = 0x00000100,
	}

	/// <summary>Used by the <see cref="SYSTEM_CPU_SET_INFORMATION"/> structure.</summary>
	[Flags]
	public enum SYSTEM_CPU_SET_FLAGS : byte
	{
		/// <summary>
		/// If set, the home processor of this CPU Set is parked. If the CPU Set is on a parked processor, threads assigned to that set may
		/// be reassigned to other processors that are selected by the Process Default sets or the Thread Selected sets. If all such
		/// processors are parked, the threads are reassigned to other available processors on the system.
		/// </summary>
		SYSTEM_CPU_SET_INFORMATION_PARKED = 0x1,

		/// <summary>
		/// If set, the specified CPU Set is not available for general system use, but instead is allocated for exclusive use of some
		/// processes. If a non-NULL Process argument is specified in a call to GetSystemCpuSetInformation, it is possible to determine if
		/// the processor is allocated for use with that process.
		/// </summary>
		SYSTEM_CPU_SET_INFORMATION_ALLOCATED = 0x2,

		/// <summary>
		/// This is set if the CPU Set is allocated for the exclusive use of some subset of the system processes and if it is allocated for
		/// the use of the process passed into GetSystemCpuSetInformation.
		/// </summary>
		SYSTEM_CPU_SET_INFORMATION_ALLOCATED_TO_TARGET_PROCESS = 0x4,

		/// <summary>
		/// This is set of the CPU Set is on a processor that is suitable for low-latency realtime processing. The system takes steps to
		/// ensure that RealTime CPU Sets are unlikely to be running non-preemptible code, by moving other work like Interrupts and other
		/// application threads off of those processors.
		/// </summary>
		SYSTEM_CPU_SET_INFORMATION_REALTIME = 0x8,
	}

	/// <summary></summary>
	public enum THREAD_INFORMATION_CLASS
	{
		/// <summary>The thread memory priority</summary>
		[CorrespondingType(typeof(MEMORY_PRIORITY_INFORMATION), CorrespondingAction.GetSet)]
		ThreadMemoryPriority,

		/// <summary>The thread absolute cpu priority</summary>
		ThreadAbsoluteCpuPriority,

		/// <summary>The thread dynamic code policy</summary>
		ThreadDynamicCodePolicy,

		/// <summary>The thread power throttling</summary>
		[CorrespondingType(typeof(THREAD_POWER_THROTTLING_STATE), CorrespondingAction.Set)] // TODO: Figure out why Get doesn't work
		ThreadPowerThrottling,
	}

	/// <summary>The thread's priority level.</summary>
	public enum THREAD_PRIORITY
	{
		/// <summary>Priority 2 points below the priority class.</summary>
		THREAD_PRIORITY_LOWEST = -2,

		/// <summary>Priority 1 point below the priority class.</summary>
		THREAD_PRIORITY_BELOW_NORMAL = THREAD_PRIORITY_LOWEST + 1,

		/// <summary>Normal priority for the priority class.</summary>
		THREAD_PRIORITY_NORMAL = 0,

		/// <summary>Priority 2 points above the priority class.</summary>
		THREAD_PRIORITY_HIGHEST = 2,

		/// <summary>Priority 1 point above the priority class.</summary>
		THREAD_PRIORITY_ABOVE_NORMAL = THREAD_PRIORITY_HIGHEST - 1,

		/// <summary>The thread priority error return</summary>
		THREAD_PRIORITY_ERROR_RETURN = 0x7fffffff,

		/// <summary>
		/// Base-priority level of 15 for IDLE_PRIORITY_CLASS, BELOW_NORMAL_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS,
		/// ABOVE_NORMAL_PRIORITY_CLASS, or HIGH_PRIORITY_CLASS processes, and a base-priority level of 31 for REALTIME_PRIORITY_CLASS processes.
		/// </summary>
		THREAD_PRIORITY_TIME_CRITICAL = 15,

		/// <summary>
		/// Base priority of 1 for IDLE_PRIORITY_CLASS, BELOW_NORMAL_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, ABOVE_NORMAL_PRIORITY_CLASS, or
		/// HIGH_PRIORITY_CLASS processes, and a base priority of 16 for REALTIME_PRIORITY_CLASS processes.
		/// </summary>
		THREAD_PRIORITY_IDLE = -15,

		/// <summary>The thread mode background begin</summary>
		THREAD_MODE_BACKGROUND_BEGIN = 0x00010000,

		/// <summary>The thread mode background end</summary>
		THREAD_MODE_BACKGROUND_END = 0x00020000,
	}

	/// <summary>
	/// <para>
	/// Microsoft Windows enables you to control access to thread objects. For more information about security, see Access-Control Model.
	/// </para>
	/// <para>
	/// You can specify a security descriptor for a thread when you call the <c>CreateProcess</c>, <c>CreateProcessAsUser</c>,
	/// <c>CreateProcessWithLogonW</c>, <c>CreateThread</c>, or <c>CreateRemoteThread</c> function. If you specify <c>NULL</c>, the thread
	/// gets a default security descriptor. The ACLs in the default security descriptor for a thread come from the primary or impersonation
	/// token of the creator.
	/// </para>
	/// <para>
	/// To retrieve a thread's security descriptor, call the <c>GetSecurityInfo</c> function. To change a thread's security descriptor, call
	/// the <c>SetSecurityInfo</c> function.
	/// </para>
	/// <para>
	/// The handle returned by the <c>CreateThread</c> function has <c>THREAD_ALL_ACCESS</c> access to the thread object. When you call the
	/// <c>GetCurrentThread</c> function, the system returns a pseudohandle with the maximum access that the thread's security descriptor
	/// allows the caller.
	/// </para>
	/// <para>
	/// The valid access rights for thread objects include the standard access rights and some thread-specific access rights. The following
	/// table lists the standard access rights used by all objects.
	/// </para>
	/// <list type="table">
	/// <listheader>
	/// <term>Value</term>
	/// <term>Meaning</term>
	/// </listheader>
	/// <item>
	/// <term>DELETE (0x00010000L)</term>
	/// <term>Required to delete the object.</term>
	/// </item>
	/// <item>
	/// <term>READ_CONTROL (0x00020000L)</term>
	/// <term>
	/// Required to read information in the security descriptor for the object, not including the information in the SACL. To read or write
	/// the SACL, you must request the ACCESS_SYSTEM_SECURITY access right. For more information, see SACL Access Right.
	/// </term>
	/// </item>
	/// <item>
	/// <term>SYNCHRONIZE (0x00100000L)</term>
	/// <term>The right to use the object for synchronization. This enables a thread to wait until the object is in the signaled state.</term>
	/// </item>
	/// <item>
	/// <term>WRITE_DAC (0x00040000L)</term>
	/// <term>Required to modify the DACL in the security descriptor for the object.</term>
	/// </item>
	/// <item>
	/// <term>WRITE_OWNER (0x00080000L)</term>
	/// <term>Required to change the owner in the security descriptor for the object.</term>
	/// </item>
	/// </list>
	/// <para>The following table lists the thread-specific access rights.</para>
	/// <list type="table">
	/// <listheader>
	/// <term>Value</term>
	/// <term>Meaning</term>
	/// </listheader>
	/// <item>
	/// <term>SYNCHRONIZE (0x00100000L)</term>
	/// <term>Enables the use of the thread handle in any of the wait functions.</term>
	/// </item>
	/// <item>
	/// <term>THREAD_ALL_ACCESS</term>
	/// <term>
	/// All possible access rights for a thread object.Windows Server 2003 and Windows XP: The value of the THREAD_ALL_ACCESS flag increased
	/// on Windows Server 2008 and Windows Vista. If an application compiled for Windows Server 2008 and Windows Vista is run on Windows
	/// Server 2003 or Windows XP, the THREAD_ALL_ACCESS flag contains access bits that are not supported and the function specifying this
	/// flag fails with ERROR_ACCESS_DENIED. To avoid this problem, specify the minimum set of access rights required for the operation. If
	/// THREAD_ALL_ACCESS must be used, set _WIN32_WINNT to the minimum operating system targeted by your application (for example, ). For
	/// more information, see Using the Windows Headers.
	/// </term>
	/// </item>
	/// <item>
	/// <term>THREAD_DIRECT_IMPERSONATION (0x0200)</term>
	/// <term>Required for a server thread that impersonates a client.</term>
	/// </item>
	/// <item>
	/// <term>THREAD_GET_CONTEXT (0x0008)</term>
	/// <term>Required to read the context of a thread using GetThreadContext.</term>
	/// </item>
	/// <item>
	/// <term>THREAD_IMPERSONATE (0x0100)</term>
	/// <term>
	/// Required to use a thread's security information directly without calling it by using a communication mechanism that provides
	/// impersonation services.
	/// </term>
	/// </item>
	/// <item>
	/// <term>THREAD_QUERY_INFORMATION (0x0040)</term>
	/// <term>Required to read certain information from the thread object, such as the exit code (see GetExitCodeThread).</term>
	/// </item>
	/// <item>
	/// <term>THREAD_QUERY_LIMITED_INFORMATION (0x0800)</term>
	/// <term>
	/// Required to read certain information from the thread objects (see GetProcessIdOfThread). A handle that has the
	/// THREAD_QUERY_INFORMATION access right is automatically granted THREAD_QUERY_LIMITED_INFORMATION.Windows Server 2003 and Windows XP:
	/// This access right is not supported.
	/// </term>
	/// </item>
	/// <item>
	/// <term>THREAD_SET_CONTEXT (0x0010)</term>
	/// <term>Required to write the context of a thread using SetThreadContext.</term>
	/// </item>
	/// <item>
	/// <term>THREAD_SET_INFORMATION (0x0020)</term>
	/// <term>Required to set certain information in the thread object.</term>
	/// </item>
	/// <item>
	/// <term>THREAD_SET_LIMITED_INFORMATION (0x0400)</term>
	/// <term>
	/// Required to set certain information in the thread object. A handle that has the THREAD_SET_INFORMATION access right is automatically
	/// granted THREAD_SET_LIMITED_INFORMATION.Windows Server 2003 and Windows XP: This access right is not supported.
	/// </term>
	/// </item>
	/// <item>
	/// <term>THREAD_SET_THREAD_TOKEN (0x0080)</term>
	/// <term>Required to set the impersonation token for a thread using SetThreadToken.</term>
	/// </item>
	/// <item>
	/// <term>THREAD_SUSPEND_RESUME (0x0002)</term>
	/// <term>Required to suspend or resume a thread (see SuspendThread and ResumeThread).</term>
	/// </item>
	/// <item>
	/// <term>THREAD_TERMINATE (0x0001)</term>
	/// <term>Required to terminate a thread using TerminateThread.</term>
	/// </item>
	/// </list>
	/// <para>
	/// You can request the <c>ACCESS_SYSTEM_SECURITY</c> access right to a thread object if you want to read or write the object's SACL. For
	/// more information, see Access-Control Lists (ACLs) and SACL Access Right.
	/// </para>
	/// </summary>
	// https://docs.microsoft.com/en-us/windows/win32/procthread/thread-security-and-access-rights
	[PInvokeData("", MSDNShortId = "72709446-5c59-4fac-8dc8-7912906ecc85")]
	[Flags]
	public enum ThreadAccess : uint
	{
		/// <term>Required to terminate a thread using TerminateThread.</term>
		THREAD_TERMINATE = 0x0001,

		/// <term>Required to suspend or resume a thread (see SuspendThread and ResumeThread).</term>
		THREAD_SUSPEND_RESUME = 0x0002,

		/// <term>Required to read the context of a thread using GetThreadContext.</term>
		THREAD_GET_CONTEXT = 0x0008,

		/// <term>Required to write the context of a thread using SetThreadContext.</term>
		THREAD_SET_CONTEXT = 0x0010,

		/// <term>Required to read certain information from the thread object, such as the exit code (see GetExitCodeThread).</term>
		THREAD_QUERY_INFORMATION = 0x0040,

		/// <term>Required to set certain information in the thread object.</term>
		THREAD_SET_INFORMATION = 0x0020,

		/// <term>Required to set the impersonation token for a thread using SetThreadToken.</term>
		THREAD_SET_THREAD_TOKEN = 0x0080,

		/// <term>
		/// Required to use a thread's security information directly without calling it by using a communication mechanism that provides
		/// impersonation services.
		/// </term>
		THREAD_IMPERSONATE = 0x0100,

		/// <term>Required for a server thread that impersonates a client.</term>
		THREAD_DIRECT_IMPERSONATION = 0x0200,

		/// <term>
		/// Required to set certain information in the thread object. A handle that has the THREAD_SET_INFORMATION access right is
		/// automatically granted THREAD_SET_LIMITED_INFORMATION.Windows Server 2003 and Windows XP: This access right is not supported.
		/// </term>
		THREAD_SET_LIMITED_INFORMATION = 0x0400,

		/// <term>
		/// Required to read certain information from the thread objects (see GetProcessIdOfThread). A handle that has the
		/// THREAD_QUERY_INFORMATION access right is automatically granted THREAD_QUERY_LIMITED_INFORMATION.Windows Server 2003 and Windows
		/// XP: This access right is not supported.
		/// </term>
		THREAD_QUERY_LIMITED_INFORMATION = 0x0800,

		/// <term>Required to resume a thread (see ResumeThread).</term>
		THREAD_RESUME = 0x1000,

		/// <term>
		/// All possible access rights for a thread object.Windows Server 2003 and Windows XP: The value of the THREAD_ALL_ACCESS flag
		/// increased on Windows Server 2008 and Windows Vista. If an application compiled for Windows Server 2008 and Windows Vista is run
		/// on Windows Server 2003 or Windows XP, the THREAD_ALL_ACCESS flag contains access bits that are not supported and the function
		/// specifying this flag fails with ERROR_ACCESS_DENIED. To avoid this problem, specify the minimum set of access rights required for
		/// the operation. If THREAD_ALL_ACCESS must be used, set _WIN32_WINNT to the minimum operating system targeted by your application
		/// (for example, ). For more information, see Using the Windows Headers.
		/// </term>
		THREAD_ALL_ACCESS = ACCESS_MASK.STANDARD_RIGHTS_REQUIRED | ACCESS_MASK.SYNCHRONIZE | 0xFFFF
	}

	/// <summary>
	/// <para>Creates a new process and its primary thread. The new process runs in the security context of the calling process.</para>
	/// <para>
	/// If the calling process is impersonating another user, the new process uses the token for the calling process, not the impersonation
	/// token. To run the new process in the security context of the user represented by the impersonation token, use the
	/// <c>CreateProcessAsUser</c> or <c>CreateProcessWithLogonW</c> function.
	/// </para>
	/// </summary>
	/// <param name="lpApplicationName">
	/// <para>
	/// The name of the module to be executed. This module can be a Windows-based application. It can be some other type of module (for
	/// example, MS-DOS or OS/2) if the appropriate subsystem is available on the local computer.
	/// </para>
	/// <para>
	/// The string can specify the full path and file name of the module to execute or it can specify a partial name. In the case of a
	/// partial name, the function uses the current drive and current directory to complete the specification. The function will not use the
	/// search path. This parameter must include the file name extension; no default extension is assumed.
	/// </para>
	/// <para>
	/// The lpApplicationName parameter can be <c>NULL</c>. In that case, the module name must be the first white space–delimited token in
	/// the lpCommandLine string. If you are using a long file name that contains a space, use quoted strings to indicate where the file name
	/// ends and the arguments begin; otherwise, the file name is ambiguous. For example, consider the string "c:\program files\sub
	/// dir\program name". This string can be interpreted in a number of ways. The system tries to interpret the possibilities in the
	/// following order:
	/// </para>
	/// <para>
	/// If the executable module is a 16-bit application, lpApplicationName should be <c>NULL</c>, and the string pointed to by lpCommandLine
	/// should specify the executable module as well as its arguments.
	/// </para>
	/// <para>
	/// To run a batch file, you must start the command interpreter; set lpApplicationName to cmd.exe and set lpCommandLine to the following
	/// arguments: /c plus the name of the batch file.
	/// </para>
	/// </param>
	/// <param name="lpCommandLine">
	/// <para>
	/// The command line to be executed. The maximum length of this string is 32,768 characters, including the Unicode terminating null
	/// character. If lpApplicationName is <c>NULL</c>, the module name portion of lpCommandLine is limited to <c>MAX_PATH</c> characters.
	/// </para>
	/// <para>
	/// The Unicode version of this function, <c>CreateProcessW</c>, can modify the contents of this string. Therefore, this parameter cannot
	/// be a pointer to read-only memory (such as a <c>const</c> variable or a literal string). If this parameter is a constant string, the
	/// function may cause an access violation.
	/// </para>
	/// <para>
	/// The lpCommandLine parameter can be NULL. In that case, the function uses the string pointed to by lpApplicationName as the command line.
	/// </para>
	/// <para>
	/// If both lpApplicationName and lpCommandLine are non- <c>NULL</c>, the null-terminated string pointed to by lpApplicationName
	/// specifies the module to execute, and the null-terminated string pointed to by lpCommandLine specifies the command line. The new
	/// process can use <c>GetCommandLine</c> to retrieve the entire command line. Console processes written in C can use the argc and argv
	/// arguments to parse the command line. Because argv[0] is the module name, C programmers generally repeat the module name as the first
	/// token in the command line.
	/// </para>
	/// <para>
	/// If lpApplicationName is NULL, the first white space–delimited token of the command line specifies the module name. If you are using a
	/// long file name that contains a space, use quoted strings to indicate where the file name ends and the arguments begin (see the
	/// explanation for the lpApplicationName parameter). If the file name does not contain an extension, .exe is appended. Therefore, if the
	/// file name extension is .com, this parameter must include the .com extension. If the file name ends in a period (.) with no extension,
	/// or if the file name contains a path, .exe is not appended. If the file name does not contain a directory path, the system searches
	/// for the executable file in the following sequence:
	/// </para>
	/// <para>
	/// The system adds a terminating null character to the command-line string to separate the file name from the arguments. This divides
	/// the original string into two strings for internal processing.
	/// </para>
	/// </param>
	/// <param name="lpProcessAttributes">
	/// <para>
	/// A pointer to a <c>SECURITY_ATTRIBUTES</c> structure that determines whether the returned handle to the new process object can be
	/// inherited by child processes. If lpProcessAttributes is <c>NULL</c>, the handle cannot be inherited.
	/// </para>
	/// <para>
	/// The <c>lpSecurityDescriptor</c> member of the structure specifies a security descriptor for the new process. If lpProcessAttributes
	/// is NULL or <c>lpSecurityDescriptor</c> is <c>NULL</c>, the process gets a default security descriptor. The ACLs in the default
	/// security descriptor for a process come from the primary token of the creator.
	/// </para>
	/// <para>
	/// <c>Windows XP:</c> The ACLs in the default security descriptor for a process come from the primary or impersonation token of the
	/// creator. This behavior changed with Windows XP with SP2 and Windows Server 2003.
	/// </para>
	/// </param>
	/// <param name="lpThreadAttributes">
	/// <para>
	/// A pointer to a <c>SECURITY_ATTRIBUTES</c> structure that determines whether the returned handle to the new thread object can be
	/// inherited by child processes. If lpThreadAttributes is NULL, the handle cannot be inherited.
	/// </para>
	/// <para>
	/// The <c>lpSecurityDescriptor</c> member of the structure specifies a security descriptor for the main thread. If lpThreadAttributes is
	/// NULL or <c>lpSecurityDescriptor</c> is NULL, the thread gets a default security descriptor. The ACLs in the default security
	/// descriptor for a thread come from the process token.
	/// </para>
	/// <para>
	/// <c>Windows XP:</c> The ACLs in the default security descriptor for a thread come from the primary or impersonation token of the
	/// creator. This behavior changed with Windows XP with SP2 and Windows Server 2003.
	/// </para>
	/// </param>
	/// <param name="bInheritHandles">
	/// <para>
	/// If this parameter is TRUE, each inheritable handle in the calling process is inherited by the new process. If the parameter is FALSE,
	/// the handles are not inherited. Note that inherited handles have the same value and access rights as the original handles.
	/// </para>
	/// <para>
	/// <c>Terminal Services:</c> You cannot inherit handles across sessions. Additionally, if this parameter is TRUE, you must create the
	/// process in the same session as the caller.
	/// </para>
	/// <para>
	/// <c>Protected Process Light (PPL) processes:</c> The generic handle inheritance is blocked when a PPL process creates a non-PPL
	/// process since PROCESS_DUP_HANDLE is not allowed from a non-PPL process to a PPL process. See Process Security and Access Rights
	/// </para>
	/// </param>
	/// <param name="dwCreationFlags">
	/// <para>The flags that control the priority class and the creation of the process. For a list of values, see Process Creation Flags.</para>
	/// <para>
	/// This parameter also controls the new process's priority class, which is used to determine the scheduling priorities of the process's
	/// threads. For a list of values, see <c>GetPriorityClass</c>. If none of the priority class flags is specified, the priority class
	/// defaults to <c>NORMAL_PRIORITY_CLASS</c> unless the priority class of the creating process is <c>IDLE_PRIORITY_CLASS</c> or
	/// <c>BELOW_NORMAL_PRIORITY_CLASS</c>. In this case, the child process receives the default priority class of the calling process.
	/// </para>
	/// </param>
	/// <param name="lpEnvironment">
	/// <para>
	/// An array of the environment items for the new process. If this parameter is <c>NULL</c>, the new process uses the environment of the
	/// calling process.
	/// </para>
	/// <para>An environment item is in the following form:</para>
	/// <para>name=value\0</para>
	/// <para>Because the equal sign is used as a separator, it must not be used in the name of an environment variable.</para>
	/// <para>
	/// An environment block can contain either Unicode or ANSI characters. If the environment block pointed to by lpEnvironment contains
	/// Unicode characters, be sure that dwCreationFlags includes <c>CREATE_UNICODE_ENVIRONMENT</c>. If this parameter is <c>NULL</c> and the
	/// environment block of the parent process contains Unicode characters, you must also ensure that dwCreationFlags includes <c>CREATE_UNICODE_ENVIRONMENT</c>.
	/// </para>
	/// <para>
	/// The ANSI version of this function, <c>CreateProcessA</c> fails if the total size of the environment block for the process exceeds
	/// 32,767 characters.
	/// </para>
	/// </param>
	/// <param name="lpCurrentDirectory">
	/// <para>The full path to the current directory for the process. The string can also specify a UNC path.</para>
	/// <para>
	/// If this parameter is <c>NULL</c>, the new process will have the same current drive and directory as the calling process. (This
	/// feature is provided primarily for shells that need to start an application and specify its initial drive and working directory.)
	/// </para>
	/// </param>
	/// <param name="lpStartupInfo">
	/// <para>A pointer to a <c>STARTUPINFO</c> or <c>STARTUPINFOEX</c> structure.</para>
	/// <para>
	/// To set extended attributes, use a <c>STARTUPINFOEX</c> structure and specify EXTENDED_STARTUPINFO_PRESENT in the dwCreationFlags parameter.
	/// </para>
	/// <para>Handles in <c>STARTUPINFO</c> or <c>STARTUPINFOEX</c> must be closed with <c>CloseHandle</c> when they are no longer needed.</para>
	/// </param>
	/// <param name="lpProcessInformation">
	/// <para>A pointer to a <c>PROCESS_INFORMATION</c> structure that receives identification information about the new process.</para>
	/// <para>Handles in <c>PROCESS_INFORMATION</c> must be closed with <c>CloseHandle</c> when they are no longer needed.</para>
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
	/// <para>
	/// Note that the function returns before the process has finished initialization. If a required DLL cannot be located or fails to
	/// initialize, the process is terminated. To get the termination status of a process, call <c>GetExitCodeProcess</c>.
	/// </para>
	/// </returns>
	// BOOL WINAPI CreateProcess( _In_opt_ LPCTSTR lpApplicationName, _Inout_opt_ LPTSTR lpCommandLine, _In_opt_ LPSECURITY_ATTRIBUTES
	// lpProcessAttributes, _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, _In_ BOOL bInheritHandles, _In_ DWORD dwCreationFlags,
	// _In_opt_ LPVOID lpEnvironment, _In_opt_ LPCTSTR lpCurrentDirectory, _In_ LPSTARTUPINFO lpStartupInfo, _Out_ LPPROCESS_INFORMATION
	// lpProcessInformation); https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx
	[PInvokeData("WinBase.h", MSDNShortId = "ms682425")]
	public static bool CreateProcess([Optional] string? lpApplicationName, [Optional] StringBuilder? lpCommandLine, [In, Optional] SECURITY_ATTRIBUTES? lpProcessAttributes,
		[In, Optional] SECURITY_ATTRIBUTES? lpThreadAttributes, [Optional] bool bInheritHandles, [Optional] CREATE_PROCESS dwCreationFlags, [In, Optional] string[]? lpEnvironment,
		[Optional] string? lpCurrentDirectory, in STARTUPINFO lpStartupInfo, [AddAsCtor] out SafePROCESS_INFORMATION lpProcessInformation)
	{
		if (lpEnvironment != null && StringHelper.GetCharSize() == 2)
			dwCreationFlags |= CREATE_PROCESS.CREATE_UNICODE_ENVIRONMENT;
		bool ret = CreateProcess(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
			lpCurrentDirectory, lpStartupInfo, out PROCESS_INFORMATION pi);
		lpProcessInformation = ret ? new(pi) : new();
		return ret;
	}

	/// <summary>
	/// <para>Creates a new process and its primary thread. The new process runs in the security context of the calling process.</para>
	/// <para>
	/// If the calling process is impersonating another user, the new process uses the token for the calling process, not the impersonation
	/// token. To run the new process in the security context of the user represented by the impersonation token, use the
	/// <c>CreateProcessAsUser</c> or <c>CreateProcessWithLogonW</c> function.
	/// </para>
	/// </summary>
	/// <param name="lpCommandLine">
	/// <para>
	/// The command line to be executed. The maximum length of this string is 32,768 characters, including the Unicode terminating null
	/// character. The module name portion of lpCommandLine is limited to <c>MAX_PATH</c> characters.
	/// </para>
	/// <para>
	/// The first white space–delimited token of the command line specifies the module name. If you are using a long file name that contains
	/// a space, use quoted strings to indicate where the file name ends and the arguments begin (see the explanation for the
	/// lpApplicationName parameter). If the file name does not contain an extension, .exe is appended. Therefore, if the file name extension
	/// is .com, this parameter must include the .com extension. If the file name ends in a period (.) with no extension, or if the file name
	/// contains a path, .exe is not appended. If the file name does not contain a directory path, the system searches for the executable
	/// file in the following sequence:
	/// </para>
	/// </param>
	/// <returns>A handle to the created process.</returns>
	[PInvokeData("WinBase.h", MSDNShortId = "ms682425")]
	[return: AddAsCtor]
	public static SafeHPROCESS CreateProcess(string lpCommandLine)
	{
		if (CreateProcess(null, new StringBuilder(lpCommandLine ?? throw new ArgumentNullException(nameof(lpCommandLine))), null, null, false, 0, null, null, STARTUPINFO.Default, out PROCESS_INFORMATION pi))
		{
			CloseHandle((IntPtr)pi.hThread);
			return new SafeHPROCESS((IntPtr)pi.hProcess);
		}
		return SafeHPROCESS.Null;
	}

	/// <summary>
	/// <para>Creates a new process and its primary thread. The new process runs in the security context of the calling process.</para>
	/// <para>
	/// If the calling process is impersonating another user, the new process uses the token for the calling process, not the impersonation
	/// token. To run the new process in the security context of the user represented by the impersonation token, use the
	/// <c>CreateProcessAsUser</c> or <c>CreateProcessWithLogonW</c> function.
	/// </para>
	/// </summary>
	/// <param name="lpApplicationName">
	/// <para>
	/// The name of the module to be executed. This module can be a Windows-based application. It can be some other type of module (for
	/// example, MS-DOS or OS/2) if the appropriate subsystem is available on the local computer.
	/// </para>
	/// <para>
	/// The string can specify the full path and file name of the module to execute or it can specify a partial name. In the case of a
	/// partial name, the function uses the current drive and current directory to complete the specification. The function will not use the
	/// search path. This parameter must include the file name extension; no default extension is assumed.
	/// </para>
	/// <para>
	/// The lpApplicationName parameter can be <c>NULL</c>. In that case, the module name must be the first white space–delimited token in
	/// the lpCommandLine string. If you are using a long file name that contains a space, use quoted strings to indicate where the file name
	/// ends and the arguments begin; otherwise, the file name is ambiguous. For example, consider the string "c:\program files\sub
	/// dir\program name". This string can be interpreted in a number of ways. The system tries to interpret the possibilities in the
	/// following order:
	/// </para>
	/// <para>
	/// If the executable module is a 16-bit application, lpApplicationName should be <c>NULL</c>, and the string pointed to by lpCommandLine
	/// should specify the executable module as well as its arguments.
	/// </para>
	/// <para>
	/// To run a batch file, you must start the command interpreter; set lpApplicationName to cmd.exe and set lpCommandLine to the following
	/// arguments: /c plus the name of the batch file.
	/// </para>
	/// </param>
	/// <param name="lpCommandLine">
	/// <para>
	/// The command line to be executed. The maximum length of this string is 32,768 characters, including the Unicode terminating null
	/// character. If lpApplicationName is <c>NULL</c>, the module name portion of lpCommandLine is limited to <c>MAX_PATH</c> characters.
	/// </para>
	/// <para>
	/// The Unicode version of this function, <c>CreateProcessW</c>, can modify the contents of this string. Therefore, this parameter cannot
	/// be a pointer to read-only memory (such as a <c>const</c> variable or a literal string). If this parameter is a constant string, the
	/// function may cause an access violation.
	/// </para>
	/// <para>
	/// The lpCommandLine parameter can be NULL. In that case, the function uses the string pointed to by lpApplicationName as the command line.
	/// </para>
	/// <para>
	/// If both lpApplicationName and lpCommandLine are non- <c>NULL</c>, the null-terminated string pointed to by lpApplicationName
	/// specifies the module to execute, and the null-terminated string pointed to by lpCommandLine specifies the command line. The new
	/// process can use <c>GetCommandLine</c> to retrieve the entire command line. Console processes written in C can use the argc and argv
	/// arguments to parse the command line. Because argv[0] is the module name, C programmers generally repeat the module name as the first
	/// token in the command line.
	/// </para>
	/// <para>
	/// If lpApplicationName is NULL, the first white space–delimited token of the command line specifies the module name. If you are using a
	/// long file name that contains a space, use quoted strings to indicate where the file name ends and the arguments begin (see the
	/// explanation for the lpApplicationName parameter). If the file name does not contain an extension, .exe is appended. Therefore, if the
	/// file name extension is .com, this parameter must include the .com extension. If the file name ends in a period (.) with no extension,
	/// or if the file name contains a path, .exe is not appended. If the file name does not contain a directory path, the system searches
	/// for the executable file in the following sequence:
	/// </para>
	/// <para>
	/// The system adds a terminating null character to the command-line string to separate the file name from the arguments. This divides
	/// the original string into two strings for internal processing.
	/// </para>
	/// </param>
	/// <param name="lpProcessAttributes">
	/// <para>
	/// A pointer to a <c>SECURITY_ATTRIBUTES</c> structure that determines whether the returned handle to the new process object can be
	/// inherited by child processes. If lpProcessAttributes is <c>NULL</c>, the handle cannot be inherited.
	/// </para>
	/// <para>
	/// The <c>lpSecurityDescriptor</c> member of the structure specifies a security descriptor for the new process. If lpProcessAttributes
	/// is NULL or <c>lpSecurityDescriptor</c> is <c>NULL</c>, the process gets a default security descriptor. The ACLs in the default
	/// security descriptor for a process come from the primary token of the creator.
	/// </para>
	/// <para>
	/// <c>Windows XP:</c> The ACLs in the default security descriptor for a process come from the primary or impersonation token of the
	/// creator. This behavior changed with Windows XP with SP2 and Windows Server 2003.
	/// </para>
	/// </param>
	/// <param name="lpThreadAttributes">
	/// <para>
	/// A pointer to a <c>SECURITY_ATTRIBUTES</c> structure that determines whether the returned handle to the new thread object can be
	/// inherited by child processes. If lpThreadAttributes is NULL, the handle cannot be inherited.
	/// </para>
	/// <para>
	/// The <c>lpSecurityDescriptor</c> member of the structure specifies a security descriptor for the main thread. If lpThreadAttributes is
	/// NULL or <c>lpSecurityDescriptor</c> is NULL, the thread gets a default security descriptor. The ACLs in the default security
	/// descriptor for a thread come from the process token.
	/// </para>
	/// <para>
	/// <c>Windows XP:</c> The ACLs in the default security descriptor for a thread come from the primary or impersonation token of the
	/// creator. This behavior changed with Windows XP with SP2 and Windows Server 2003.
	/// </para>
	/// </param>
	/// <param name="bInheritHandles">
	/// <para>
	/// If this parameter is TRUE, each inheritable handle in the calling process is inherited by the new process. If the parameter is FALSE,
	/// the handles are not inherited. Note that inherited handles have the same value and access rights as the original handles.
	/// </para>
	/// <para>
	/// <c>Terminal Services:</c> You cannot inherit handles across sessions. Additionally, if this parameter is TRUE, you must create the
	/// process in the same session as the caller.
	/// </para>
	/// <para>
	/// <c>Protected Process Light (PPL) processes:</c> The generic handle inheritance is blocked when a PPL process creates a non-PPL
	/// process since PROCESS_DUP_HANDLE is not allowed from a non-PPL process to a PPL process. See Process Security and Access Rights
	/// </para>
	/// </param>
	/// <param name="dwCreationFlags">
	/// <para>The flags that control the priority class and the creation of the process. For a list of values, see Process Creation Flags.</para>
	/// <para>
	/// This parameter also controls the new process's priority class, which is used to determine the scheduling priorities of the process's
	/// threads. For a list of values, see <c>GetPriorityClass</c>. If none of the priority class flags is specified, the priority class
	/// defaults to <c>NORMAL_PRIORITY_CLASS</c> unless the priority class of the creating process is <c>IDLE_PRIORITY_CLASS</c> or
	/// <c>BELOW_NORMAL_PRIORITY_CLASS</c>. In this case, the child process receives the default priority class of the calling process.
	/// </para>
	/// </param>
	/// <param name="lpEnvironment">
	/// <para>
	/// An array of the environment items for the new process. If this parameter is <c>NULL</c>, the new process uses the environment of the
	/// calling process.
	/// </para>
	/// <para>An environment item is in the following form:</para>
	/// <para>name=value\0</para>
	/// <para>Because the equal sign is used as a separator, it must not be used in the name of an environment variable.</para>
	/// <para>
	/// An environment block can contain either Unicode or ANSI characters. If the environment block pointed to by lpEnvironment contains
	/// Unicode characters, be sure that dwCreationFlags includes <c>CREATE_UNICODE_ENVIRONMENT</c>. If this parameter is <c>NULL</c> and the
	/// environment block of the parent process contains Unicode characters, you must also ensure that dwCreationFlags includes <c>CREATE_UNICODE_ENVIRONMENT</c>.
	/// </para>
	/// <para>
	/// The ANSI version of this function, <c>CreateProcessA</c> fails if the total size of the environment block for the process exceeds
	/// 32,767 characters.
	/// </para>
	/// </param>
	/// <param name="lpCurrentDirectory">
	/// <para>The full path to the current directory for the process. The string can also specify a UNC path.</para>
	/// <para>
	/// If this parameter is <c>NULL</c>, the new process will have the same current drive and directory as the calling process. (This
	/// feature is provided primarily for shells that need to start an application and specify its initial drive and working directory.)
	/// </para>
	/// </param>
	/// <param name="lpStartupInfo">
	/// <para>A pointer to a <c>STARTUPINFO</c> or <c>STARTUPINFOEX</c> structure.</para>
	/// <para>
	/// To set extended attributes, use a <c>STARTUPINFOEX</c> structure and specify EXTENDED_STARTUPINFO_PRESENT in the dwCreationFlags parameter.
	/// </para>
	/// <para>Handles in <c>STARTUPINFO</c> or <c>STARTUPINFOEX</c> must be closed with <c>CloseHandle</c> when they are no longer needed.</para>
	/// </param>
	/// <param name="lpProcessInformation">
	/// <para>A pointer to a <c>PROCESS_INFORMATION</c> structure that receives identification information about the new process.</para>
	/// <para>Handles in <c>PROCESS_INFORMATION</c> must be closed with <c>CloseHandle</c> when they are no longer needed.</para>
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
	/// <para>
	/// Note that the function returns before the process has finished initialization. If a required DLL cannot be located or fails to
	/// initialize, the process is terminated. To get the termination status of a process, call <c>GetExitCodeProcess</c>.
	/// </para>
	/// </returns>
	// BOOL WINAPI CreateProcess( _In_opt_ LPCTSTR lpApplicationName, _Inout_opt_ LPTSTR lpCommandLine, _In_opt_ LPSECURITY_ATTRIBUTES
	// lpProcessAttributes, _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, _In_ BOOL bInheritHandles, _In_ DWORD dwCreationFlags,
	// _In_opt_ LPVOID lpEnvironment, _In_opt_ LPCTSTR lpCurrentDirectory, _In_ LPSTARTUPINFO lpStartupInfo, _Out_ LPPROCESS_INFORMATION
	// lpProcessInformation); https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx
	[PInvokeData("WinBase.h", MSDNShortId = "ms682425")]
	public static bool CreateProcess([Optional] string? lpApplicationName, [Optional] StringBuilder? lpCommandLine, [In, Optional] SECURITY_ATTRIBUTES? lpProcessAttributes,
		[In, Optional] SECURITY_ATTRIBUTES? lpThreadAttributes, bool bInheritHandles, [Optional] CREATE_PROCESS dwCreationFlags, [In, Optional] string[]? lpEnvironment,
		[Optional] string? lpCurrentDirectory, in STARTUPINFOEX lpStartupInfo, [AddAsCtor] out SafePROCESS_INFORMATION lpProcessInformation)
	{
		if (lpEnvironment != null && StringHelper.GetCharSize() == 2)
			dwCreationFlags |= CREATE_PROCESS.CREATE_UNICODE_ENVIRONMENT;
		bool ret = CreateProcess(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
			lpCurrentDirectory, lpStartupInfo, out PROCESS_INFORMATION pi);
		lpProcessInformation = ret ? new(pi) : new();
		return ret;
	}

	/// <summary>
	/// <para>Creates a thread that runs in the virtual address space of another process.</para>
	/// <para>
	/// Use the <c>CreateRemoteThreadEx</c> function to create a thread that runs in the virtual address space of another process and
	/// optionally specify extended attributes.
	/// </para>
	/// </summary>
	/// <param name="hProcess">
	/// A handle to the process in which the thread is to be created. The handle must have the <c>PROCESS_CREATE_THREAD</c>,
	/// <c>PROCESS_QUERY_INFORMATION</c>, <c>PROCESS_VM_OPERATION</c>, <c>PROCESS_VM_WRITE</c>, and <c>PROCESS_VM_READ</c> access rights, and
	/// may fail without these rights on certain platforms. For more information, see Process Security and Access Rights.
	/// </param>
	/// <param name="lpThreadAttributes">
	/// <para>
	/// A pointer to a <c>SECURITY_ATTRIBUTES</c> structure that specifies a security descriptor for the new thread and determines whether
	/// child processes can inherit the returned handle. If lpThreadAttributes is NULL, the thread gets a default security descriptor and the
	/// handle cannot be inherited. The access control lists (ACL) in the default security descriptor for a thread come from the primary
	/// token of the creator.
	/// </para>
	/// <para>
	/// <c>Windows XP:</c> The ACLs in the default security descriptor for a thread come from the primary or impersonation token of the
	/// creator. This behavior changed with Windows XP with SP2 and Windows Server 2003.
	/// </para>
	/// </param>
	/// <param name="dwStackSize">
	/// The initial size of the stack, in bytes. The system rounds this value to the nearest page. If this parameter is 0 (zero), the new
	/// thread uses the default size for the executable. For more information, see Thread Stack Size.
	/// </param>
	/// <param name="lpStartAddress">
	/// A pointer to the application-defined function of type <c>LPTHREAD_START_ROUTINE</c> to be executed by the thread and represents the
	/// starting address of the thread in the remote process. The function must exist in the remote process. For more information, see <c>ThreadProc</c>.
	/// </param>
	/// <param name="lpParameter">A pointer to a variable to be passed to the thread function.</param>
	/// <param name="dwCreationFlags">
	/// <para>The flags that control the creation of the thread.</para>
	/// <para>
	/// <list type="table">
	/// <listheader>
	/// <term>Value</term>
	/// <term>Meaning</term>
	/// </listheader>
	/// <item>
	/// <term>0</term>
	/// <term>The thread runs immediately after creation.</term>
	/// </item>
	/// <item>
	/// <term>CREATE_SUSPENDED0x00000004</term>
	/// <term>The thread is created in a suspended state, and does not run until the ResumeThread function is called.</term>
	/// </item>
	/// <item>
	/// <term>STACK_SIZE_PARAM_IS_A_RESERVATION0x00010000</term>
	/// <term>
	/// The dwStackSize parameter specifies the initial reserve size of the stack. If this flag is not specified, dwStackSize specifies the
	/// commit size.
	/// </term>
	/// </item>
	/// </list>
	/// </para>
	/// </param>
	/// <param name="lpThreadId">
	/// <para>A pointer to a variable that receives the thread identifier.</para>
	/// <para>If this parameter is <c>NULL</c>, the thread identifier is not returned.</para>
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is a handle to the new thread.</para>
	/// <para>If the function fails, the return value is <c>NULL</c>. To get extended error information, call <c>GetLastError</c>.</para>
	/// <para>
	/// Note that <c>CreateRemoteThread</c> may succeed even if lpStartAddress points to data, code, or is not accessible. If the start
	/// address is invalid when the thread runs, an exception occurs, and the thread terminates. Thread termination due to a invalid start
	/// address is handled as an error exit for the thread's process. This behavior is similar to the asynchronous nature of
	/// <c>CreateProcess</c>, where the process is created even if it refers to invalid or missing dynamic-link libraries (DLL).
	/// </para>
	/// </returns>
	// HANDLE WINAPI CreateRemoteThread( _In_ HANDLE hProcess, _In_ LPSECURITY_ATTRIBUTES lpThreadAttributes, _In_ SIZE_T dwStackSize, _In_
	// LPTHREAD_START_ROUTINE lpStartAddress, _In_ LPVOID lpParameter, _In_ DWORD dwCreationFlags, _Out_ LPDWORD lpThreadId); https://msdn.microsoft.com/en-us/library/windows/desktop/ms682437(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms682437")]
	[return: AddAsCtor]
	public static extern SafeHTHREAD CreateRemoteThread([In] HPROCESS hProcess, [In, Optional] SECURITY_ATTRIBUTES? lpThreadAttributes, [Optional] SizeT dwStackSize,
		ThreadProc lpStartAddress, [In, Optional] IntPtr lpParameter, [Optional] CREATE_THREAD_FLAGS dwCreationFlags, out uint lpThreadId);

	/// <summary>
	/// <para>Creates a thread that runs in the virtual address space of another process.</para>
	/// <para>
	/// Use the <c>CreateRemoteThreadEx</c> function to create a thread that runs in the virtual address space of another process and
	/// optionally specify extended attributes.
	/// </para>
	/// </summary>
	/// <param name="hProcess">
	/// A handle to the process in which the thread is to be created. The handle must have the <c>PROCESS_CREATE_THREAD</c>,
	/// <c>PROCESS_QUERY_INFORMATION</c>, <c>PROCESS_VM_OPERATION</c>, <c>PROCESS_VM_WRITE</c>, and <c>PROCESS_VM_READ</c> access rights, and
	/// may fail without these rights on certain platforms. For more information, see Process Security and Access Rights.
	/// </param>
	/// <param name="lpThreadAttributes">
	/// <para>
	/// A pointer to a <c>SECURITY_ATTRIBUTES</c> structure that specifies a security descriptor for the new thread and determines whether
	/// child processes can inherit the returned handle. If lpThreadAttributes is NULL, the thread gets a default security descriptor and the
	/// handle cannot be inherited. The access control lists (ACL) in the default security descriptor for a thread come from the primary
	/// token of the creator.
	/// </para>
	/// <para>
	/// <c>Windows XP:</c> The ACLs in the default security descriptor for a thread come from the primary or impersonation token of the
	/// creator. This behavior changed with Windows XP with SP2 and Windows Server 2003.
	/// </para>
	/// </param>
	/// <param name="dwStackSize">
	/// The initial size of the stack, in bytes. The system rounds this value to the nearest page. If this parameter is 0 (zero), the new
	/// thread uses the default size for the executable. For more information, see Thread Stack Size.
	/// </param>
	/// <param name="lpStartAddress">
	/// A pointer to the application-defined function of type <c>LPTHREAD_START_ROUTINE</c> to be executed by the thread and represents the
	/// starting address of the thread in the remote process. The function must exist in the remote process. For more information, see <c>ThreadProc</c>.
	/// </param>
	/// <param name="lpParameter">A pointer to a variable to be passed to the thread function.</param>
	/// <param name="dwCreationFlags">
	/// <para>The flags that control the creation of the thread.</para>
	/// <para>
	/// <list type="table">
	/// <listheader>
	/// <term>Value</term>
	/// <term>Meaning</term>
	/// </listheader>
	/// <item>
	/// <term>0</term>
	/// <term>The thread runs immediately after creation.</term>
	/// </item>
	/// <item>
	/// <term>CREATE_SUSPENDED0x00000004</term>
	/// <term>The thread is created in a suspended state, and does not run until the ResumeThread function is called.</term>
	/// </item>
	/// <item>
	/// <term>STACK_SIZE_PARAM_IS_A_RESERVATION0x00010000</term>
	/// <term>
	/// The dwStackSize parameter specifies the initial reserve size of the stack. If this flag is not specified, dwStackSize specifies the
	/// commit size.
	/// </term>
	/// </item>
	/// </list>
	/// </para>
	/// </param>
	/// <param name="lpThreadId">
	/// <para>A pointer to a variable that receives the thread identifier.</para>
	/// <para>If this parameter is <c>NULL</c>, the thread identifier is not returned.</para>
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is a handle to the new thread.</para>
	/// <para>If the function fails, the return value is <c>NULL</c>. To get extended error information, call <c>GetLastError</c>.</para>
	/// <para>
	/// Note that <c>CreateRemoteThread</c> may succeed even if lpStartAddress points to data, code, or is not accessible. If the start
	/// address is invalid when the thread runs, an exception occurs, and the thread terminates. Thread termination due to a invalid start
	/// address is handled as an error exit for the thread's process. This behavior is similar to the asynchronous nature of
	/// <c>CreateProcess</c>, where the process is created even if it refers to invalid or missing dynamic-link libraries (DLL).
	/// </para>
	/// </returns>
	// HANDLE WINAPI CreateRemoteThread( _In_ HANDLE hProcess, _In_ LPSECURITY_ATTRIBUTES lpThreadAttributes, _In_ SIZE_T dwStackSize, _In_
	// LPTHREAD_START_ROUTINE lpStartAddress, _In_ LPVOID lpParameter, _In_ DWORD dwCreationFlags, _Out_ LPDWORD lpThreadId); https://msdn.microsoft.com/en-us/library/windows/desktop/ms682437(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms682437")]
	[return: AddAsCtor]
	public static extern SafeHTHREAD CreateRemoteThread([In] HPROCESS hProcess, [In, Optional] SECURITY_ATTRIBUTES? lpThreadAttributes, [Optional] SizeT dwStackSize,
		IntPtr lpStartAddress, [In, Optional] IntPtr lpParameter, [Optional] CREATE_THREAD_FLAGS dwCreationFlags, out uint lpThreadId);

	/// <summary>
	/// Creates a thread that runs in the virtual address space of another process and optionally specifies extended attributes such as
	/// processor group affinity.
	/// </summary>
	/// <param name="hProcess">
	/// A handle to the process in which the thread is to be created. The handle must have the PROCESS_CREATE_THREAD,
	/// PROCESS_QUERY_INFORMATION, PROCESS_VM_OPERATION, PROCESS_VM_WRITE, and PROCESS_VM_READ access rights. In Windows 10, version 1607,
	/// your code must obtain these access rights for the new handle. However, starting in Windows 10, version 1703, if the new handle is
	/// entitled to these access rights, the system obtains them for you. For more information, see Process Security and Access Rights.
	/// </param>
	/// <param name="lpThreadAttributes">
	/// A pointer to a <c>SECURITY_ATTRIBUTES</c> structure that specifies a security descriptor for the new thread and determines whether
	/// child processes can inherit the returned handle. If lpThreadAttributes is NULL, the thread gets a default security descriptor and the
	/// handle cannot be inherited. The access control lists (ACL) in the default security descriptor for a thread come from the primary
	/// token of the creator.
	/// </param>
	/// <param name="dwStackSize">
	/// The initial size of the stack, in bytes. The system rounds this value to the nearest page. If this parameter is 0 (zero), the new
	/// thread uses the default size for the executable. For more information, see Thread Stack Size.
	/// </param>
	/// <param name="lpStartAddress">
	/// A pointer to the application-defined function of type <c>LPTHREAD_START_ROUTINE</c> to be executed by the thread and represents the
	/// starting address of the thread in the remote process. The function must exist in the remote process. For more information, see <c>ThreadProc</c>.
	/// </param>
	/// <param name="lpParameter">
	/// A pointer to a variable to be passed to the thread function pointed to by lpStartAddress. This parameter can be NULL.
	/// </param>
	/// <param name="dwCreationFlags">
	/// <para>The flags that control the creation of the thread.</para>
	/// <para>
	/// <list type="table">
	/// <listheader>
	/// <term>Value</term>
	/// <term>Meaning</term>
	/// </listheader>
	/// <item>
	/// <term>0</term>
	/// <term>The thread runs immediately after creation.</term>
	/// </item>
	/// <item>
	/// <term>CREATE_SUSPENDED0x00000004</term>
	/// <term>The thread is created in a suspended state and does not run until the ResumeThread function is called.</term>
	/// </item>
	/// <item>
	/// <term>STACK_SIZE_PARAM_IS_A_RESERVATION0x00010000</term>
	/// <term>
	/// The dwStackSize parameter specifies the initial reserve size of the stack. If this flag is not specified, dwStackSize specifies the
	/// commit size.
	/// </term>
	/// </item>
	/// </list>
	/// </para>
	/// </param>
	/// <param name="lpAttributeList">
	/// An attribute list that contains additional parameters for the new thread. This list is created by the
	/// <c>InitializeProcThreadAttributeList</c> function.
	/// </param>
	/// <param name="lpThreadId">
	/// <para>A pointer to a variable that receives the thread identifier.</para>
	/// <para>If this parameter is NULL, the thread identifier is not returned.</para>
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is a handle to the new thread.</para>
	/// <para>If the function fails, the return value is NULL. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// HANDLE CreateRemoteThreadEx( _In_ HANDLE hProcess, _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, _In_ SIZE_T dwStackSize, _In_
	// LPTHREAD_START_ROUTINE lpStartAddress, _In_opt_ LPVOID lpParameter, _In_ DWORD dwCreationFlags, _In_opt_ LPPROC_THREAD_ATTRIBUTE_LIST
	// lpAttributeList, _Out_opt_ LPDWORD lpThreadId); https://msdn.microsoft.com/en-us/library/windows/desktop/dd405484(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "dd405484")]
	public static extern SafeHTHREAD CreateRemoteThreadEx([In] HPROCESS hProcess, [In, Optional] SECURITY_ATTRIBUTES? lpThreadAttributes, [Optional] SizeT dwStackSize,
		ThreadProc lpStartAddress, [In, Optional] IntPtr lpParameter, [Optional] CREATE_THREAD_FLAGS dwCreationFlags, SafeProcThreadAttributeList lpAttributeList,
		out uint lpThreadId);

	/// <summary>
	/// Creates a thread that runs in the virtual address space of another process and optionally specifies extended attributes such as
	/// processor group affinity.
	/// </summary>
	/// <param name="hProcess">
	/// A handle to the process in which the thread is to be created. The handle must have the PROCESS_CREATE_THREAD,
	/// PROCESS_QUERY_INFORMATION, PROCESS_VM_OPERATION, PROCESS_VM_WRITE, and PROCESS_VM_READ access rights. In Windows 10, version 1607,
	/// your code must obtain these access rights for the new handle. However, starting in Windows 10, version 1703, if the new handle is
	/// entitled to these access rights, the system obtains them for you. For more information, see Process Security and Access Rights.
	/// </param>
	/// <param name="lpThreadAttributes">
	/// A pointer to a <c>SECURITY_ATTRIBUTES</c> structure that specifies a security descriptor for the new thread and determines whether
	/// child processes can inherit the returned handle. If lpThreadAttributes is NULL, the thread gets a default security descriptor and the
	/// handle cannot be inherited. The access control lists (ACL) in the default security descriptor for a thread come from the primary
	/// token of the creator.
	/// </param>
	/// <param name="dwStackSize">
	/// The initial size of the stack, in bytes. The system rounds this value to the nearest page. If this parameter is 0 (zero), the new
	/// thread uses the default size for the executable. For more information, see Thread Stack Size.
	/// </param>
	/// <param name="lpStartAddress">
	/// A pointer to the application-defined function of type <c>LPTHREAD_START_ROUTINE</c> to be executed by the thread and represents the
	/// starting address of the thread in the remote process. The function must exist in the remote process. For more information, see <c>ThreadProc</c>.
	/// </param>
	/// <param name="lpParameter">
	/// A pointer to a variable to be passed to the thread function pointed to by lpStartAddress. This parameter can be NULL.
	/// </param>
	/// <param name="dwCreationFlags">
	/// <para>The flags that control the creation of the thread.</para>
	/// <para>
	/// <list type="table">
	/// <listheader>
	/// <term>Value</term>
	/// <term>Meaning</term>
	/// </listheader>
	/// <item>
	/// <term>0</term>
	/// <term>The thread runs immediately after creation.</term>
	/// </item>
	/// <item>
	/// <term>CREATE_SUSPENDED0x00000004</term>
	/// <term>The thread is created in a suspended state and does not run until the ResumeThread function is called.</term>
	/// </item>
	/// <item>
	/// <term>STACK_SIZE_PARAM_IS_A_RESERVATION0x00010000</term>
	/// <term>
	/// The dwStackSize parameter specifies the initial reserve size of the stack. If this flag is not specified, dwStackSize specifies the
	/// commit size.
	/// </term>
	/// </item>
	/// </list>
	/// </para>
	/// </param>
	/// <param name="lpAttributeList">
	/// An attribute list that contains additional parameters for the new thread. This list is created by the
	/// <c>InitializeProcThreadAttributeList</c> function.
	/// </param>
	/// <param name="lpThreadId">
	/// <para>A pointer to a variable that receives the thread identifier.</para>
	/// <para>If this parameter is NULL, the thread identifier is not returned.</para>
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is a handle to the new thread.</para>
	/// <para>If the function fails, the return value is NULL. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// HANDLE CreateRemoteThreadEx( _In_ HANDLE hProcess, _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, _In_ SIZE_T dwStackSize, _In_
	// LPTHREAD_START_ROUTINE lpStartAddress, _In_opt_ LPVOID lpParameter, _In_ DWORD dwCreationFlags, _In_opt_ LPPROC_THREAD_ATTRIBUTE_LIST
	// lpAttributeList, _Out_opt_ LPDWORD lpThreadId); https://msdn.microsoft.com/en-us/library/windows/desktop/dd405484(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "dd405484")]
	public static extern SafeHTHREAD CreateRemoteThreadEx([In] HPROCESS hProcess, [In, Optional] SECURITY_ATTRIBUTES? lpThreadAttributes, [Optional] SizeT dwStackSize,
		ThreadProc lpStartAddress, [In, Optional] IntPtr lpParameter, [Optional] CREATE_THREAD_FLAGS dwCreationFlags, [Optional] IntPtr lpAttributeList,
		out uint lpThreadId);

	/// <summary>
	/// Creates a thread that runs in the virtual address space of another process and optionally specifies extended attributes such as
	/// processor group affinity.
	/// </summary>
	/// <param name="hProcess">
	/// A handle to the process in which the thread is to be created. The handle must have the PROCESS_CREATE_THREAD,
	/// PROCESS_QUERY_INFORMATION, PROCESS_VM_OPERATION, PROCESS_VM_WRITE, and PROCESS_VM_READ access rights. In Windows 10, version 1607,
	/// your code must obtain these access rights for the new handle. However, starting in Windows 10, version 1703, if the new handle is
	/// entitled to these access rights, the system obtains them for you. For more information, see Process Security and Access Rights.
	/// </param>
	/// <param name="lpThreadAttributes">
	/// A pointer to a <c>SECURITY_ATTRIBUTES</c> structure that specifies a security descriptor for the new thread and determines whether
	/// child processes can inherit the returned handle. If lpThreadAttributes is NULL, the thread gets a default security descriptor and the
	/// handle cannot be inherited. The access control lists (ACL) in the default security descriptor for a thread come from the primary
	/// token of the creator.
	/// </param>
	/// <param name="dwStackSize">
	/// The initial size of the stack, in bytes. The system rounds this value to the nearest page. If this parameter is 0 (zero), the new
	/// thread uses the default size for the executable. For more information, see Thread Stack Size.
	/// </param>
	/// <param name="lpStartAddress">
	/// A pointer to the application-defined function of type <c>LPTHREAD_START_ROUTINE</c> to be executed by the thread and represents the
	/// starting address of the thread in the remote process. The function must exist in the remote process. For more information, see <c>ThreadProc</c>.
	/// </param>
	/// <param name="lpParameter">
	/// A pointer to a variable to be passed to the thread function pointed to by lpStartAddress. This parameter can be NULL.
	/// </param>
	/// <param name="dwCreationFlags">
	/// <para>The flags that control the creation of the thread.</para>
	/// <para>
	/// <list type="table">
	/// <listheader>
	/// <term>Value</term>
	/// <term>Meaning</term>
	/// </listheader>
	/// <item>
	/// <term>0</term>
	/// <term>The thread runs immediately after creation.</term>
	/// </item>
	/// <item>
	/// <term>CREATE_SUSPENDED0x00000004</term>
	/// <term>The thread is created in a suspended state and does not run until the ResumeThread function is called.</term>
	/// </item>
	/// <item>
	/// <term>STACK_SIZE_PARAM_IS_A_RESERVATION0x00010000</term>
	/// <term>
	/// The dwStackSize parameter specifies the initial reserve size of the stack. If this flag is not specified, dwStackSize specifies the
	/// commit size.
	/// </term>
	/// </item>
	/// </list>
	/// </para>
	/// </param>
	/// <param name="lpAttributeList">
	/// An attribute list that contains additional parameters for the new thread. This list is created by the
	/// <c>InitializeProcThreadAttributeList</c> function.
	/// </param>
	/// <param name="lpThreadId">
	/// <para>A pointer to a variable that receives the thread identifier.</para>
	/// <para>If this parameter is NULL, the thread identifier is not returned.</para>
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is a handle to the new thread.</para>
	/// <para>If the function fails, the return value is NULL. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// HANDLE CreateRemoteThreadEx( _In_ HANDLE hProcess, _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, _In_ SIZE_T dwStackSize, _In_
	// LPTHREAD_START_ROUTINE lpStartAddress, _In_opt_ LPVOID lpParameter, _In_ DWORD dwCreationFlags, _In_opt_ LPPROC_THREAD_ATTRIBUTE_LIST
	// lpAttributeList, _Out_opt_ LPDWORD lpThreadId); https://msdn.microsoft.com/en-us/library/windows/desktop/dd405484(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "dd405484")]
	public static extern SafeHTHREAD CreateRemoteThreadEx([In] HPROCESS hProcess, [In, Optional] SECURITY_ATTRIBUTES? lpThreadAttributes, [Optional] SizeT dwStackSize,
		IntPtr lpStartAddress, [In, Optional] IntPtr lpParameter, [Optional] CREATE_THREAD_FLAGS dwCreationFlags, SafeProcThreadAttributeList lpAttributeList,
		out uint lpThreadId);

	/// <summary>
	/// Creates a thread that runs in the virtual address space of another process and optionally specifies extended attributes such as
	/// processor group affinity.
	/// </summary>
	/// <param name="hProcess">
	/// A handle to the process in which the thread is to be created. The handle must have the PROCESS_CREATE_THREAD,
	/// PROCESS_QUERY_INFORMATION, PROCESS_VM_OPERATION, PROCESS_VM_WRITE, and PROCESS_VM_READ access rights. In Windows 10, version 1607,
	/// your code must obtain these access rights for the new handle. However, starting in Windows 10, version 1703, if the new handle is
	/// entitled to these access rights, the system obtains them for you. For more information, see Process Security and Access Rights.
	/// </param>
	/// <param name="lpThreadAttributes">
	/// A pointer to a <c>SECURITY_ATTRIBUTES</c> structure that specifies a security descriptor for the new thread and determines whether
	/// child processes can inherit the returned handle. If lpThreadAttributes is NULL, the thread gets a default security descriptor and the
	/// handle cannot be inherited. The access control lists (ACL) in the default security descriptor for a thread come from the primary
	/// token of the creator.
	/// </param>
	/// <param name="dwStackSize">
	/// The initial size of the stack, in bytes. The system rounds this value to the nearest page. If this parameter is 0 (zero), the new
	/// thread uses the default size for the executable. For more information, see Thread Stack Size.
	/// </param>
	/// <param name="lpStartAddress">
	/// A pointer to the application-defined function of type <c>LPTHREAD_START_ROUTINE</c> to be executed by the thread and represents the
	/// starting address of the thread in the remote process. The function must exist in the remote process. For more information, see <c>ThreadProc</c>.
	/// </param>
	/// <param name="lpParameter">
	/// A pointer to a variable to be passed to the thread function pointed to by lpStartAddress. This parameter can be NULL.
	/// </param>
	/// <param name="dwCreationFlags">
	/// <para>The flags that control the creation of the thread.</para>
	/// <para>
	/// <list type="table">
	/// <listheader>
	/// <term>Value</term>
	/// <term>Meaning</term>
	/// </listheader>
	/// <item>
	/// <term>0</term>
	/// <term>The thread runs immediately after creation.</term>
	/// </item>
	/// <item>
	/// <term>CREATE_SUSPENDED0x00000004</term>
	/// <term>The thread is created in a suspended state and does not run until the ResumeThread function is called.</term>
	/// </item>
	/// <item>
	/// <term>STACK_SIZE_PARAM_IS_A_RESERVATION0x00010000</term>
	/// <term>
	/// The dwStackSize parameter specifies the initial reserve size of the stack. If this flag is not specified, dwStackSize specifies the
	/// commit size.
	/// </term>
	/// </item>
	/// </list>
	/// </para>
	/// </param>
	/// <param name="lpAttributeList">
	/// An attribute list that contains additional parameters for the new thread. This list is created by the
	/// <c>InitializeProcThreadAttributeList</c> function.
	/// </param>
	/// <param name="lpThreadId">
	/// <para>A pointer to a variable that receives the thread identifier.</para>
	/// <para>If this parameter is NULL, the thread identifier is not returned.</para>
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is a handle to the new thread.</para>
	/// <para>If the function fails, the return value is NULL. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// HANDLE CreateRemoteThreadEx( _In_ HANDLE hProcess, _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, _In_ SIZE_T dwStackSize, _In_
	// LPTHREAD_START_ROUTINE lpStartAddress, _In_opt_ LPVOID lpParameter, _In_ DWORD dwCreationFlags, _In_opt_ LPPROC_THREAD_ATTRIBUTE_LIST
	// lpAttributeList, _Out_opt_ LPDWORD lpThreadId); https://msdn.microsoft.com/en-us/library/windows/desktop/dd405484(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "dd405484")]
	public static extern SafeHTHREAD CreateRemoteThreadEx([In] HPROCESS hProcess, [In, Optional] SECURITY_ATTRIBUTES? lpThreadAttributes, [Optional] SizeT dwStackSize,
		IntPtr lpStartAddress, [In, Optional] IntPtr lpParameter, [Optional] CREATE_THREAD_FLAGS dwCreationFlags, [Optional] IntPtr lpAttributeList,
		out uint lpThreadId);

	/// <summary>
	/// Creates a thread that runs in the virtual address space of another process and optionally specifies extended attributes such as
	/// processor group affinity.
	/// </summary>
	/// <param name="hProcess">
	/// A handle to the process in which the thread is to be created. The handle must have the PROCESS_CREATE_THREAD,
	/// PROCESS_QUERY_INFORMATION, PROCESS_VM_OPERATION, PROCESS_VM_WRITE, and PROCESS_VM_READ access rights. In Windows 10, version 1607,
	/// your code must obtain these access rights for the new handle. However, starting in Windows 10, version 1703, if the new handle is
	/// entitled to these access rights, the system obtains them for you. For more information, see Process Security and Access Rights.
	/// </param>
	/// <param name="lpThreadAttributes">
	/// A pointer to a <c>SECURITY_ATTRIBUTES</c> structure that specifies a security descriptor for the new thread and determines whether
	/// child processes can inherit the returned handle. If lpThreadAttributes is NULL, the thread gets a default security descriptor and the
	/// handle cannot be inherited. The access control lists (ACL) in the default security descriptor for a thread come from the primary
	/// token of the creator.
	/// </param>
	/// <param name="lpStartAddress">
	/// A pointer to the application-defined function of type <c>LPTHREAD_START_ROUTINE</c> to be executed by the thread and represents the
	/// starting address of the thread in the remote process. The function must exist in the remote process. For more information, see <c>ThreadProc</c>.
	/// </param>
	/// <param name="lpParameter">
	/// A pointer to a variable to be passed to the thread function pointed to by lpStartAddress. This parameter can be NULL.
	/// </param>
	/// <param name="dwStackSize">
	/// The initial size of the stack, in bytes. The system rounds this value to the nearest page. If this parameter is 0 (zero), the new
	/// thread uses the default size for the executable. For more information, see Thread Stack Size.
	/// </param>
	/// <param name="dwCreationFlags">
	/// <para>The flags that control the creation of the thread.</para>
	/// <para>
	/// <list type="table">
	/// <listheader>
	/// <term>Value</term>
	/// <term>Meaning</term>
	/// </listheader>
	/// <item>
	/// <term>0</term>
	/// <term>The thread runs immediately after creation.</term>
	/// </item>
	/// <item>
	/// <term>CREATE_SUSPENDED = 0x00000004</term>
	/// <term>The thread is created in a suspended state and does not run until the ResumeThread function is called.</term>
	/// </item>
	/// <item>
	/// <term>STACK_SIZE_PARAM_IS_A_RESERVATION = 0x00010000</term>
	/// <term>
	/// The dwStackSize parameter specifies the initial reserve size of the stack. If this flag is not specified, dwStackSize specifies the
	/// commit size.
	/// </term>
	/// </item>
	/// </list>
	/// </para>
	/// </param>
	/// <param name="lpThreadId">A pointer to a variable that receives the thread identifier.</param>
	/// <param name="lpAttributeList">An attribute list that contains additional parameters for the new thread.</param>
	/// <returns>
	/// <para>If the function succeeds, the return value is a handle to the new thread.</para>
	/// <para>If the function fails, the return value is NULL. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	[PInvokeData("WinBase.h", MSDNShortId = "dd405484")]
	[return: AddAsCtor]
	public static SafeHTHREAD CreateRemoteThreadEx([In, AddAsMember] HPROCESS hProcess, [In, Optional] SECURITY_ATTRIBUTES? lpThreadAttributes,
		ThreadProc lpStartAddress, [In, Optional] IntPtr lpParameter, [Optional] SizeT dwStackSize, [Optional] CREATE_THREAD_FLAGS dwCreationFlags,
		out uint lpThreadId, params (PROC_THREAD_ATTRIBUTE attribute, object value)[] lpAttributeList)
	{
		using var al = SafeProcThreadAttributeList.Create(lpAttributeList.ToDictionary(x => x.attribute, x => x.value));
		return CreateRemoteThreadEx(hProcess, lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, al, out lpThreadId);
	}

	/// <summary>
	/// <para>Creates a thread to execute within the virtual address space of the calling process.</para>
	/// <para>To create a thread that runs in the virtual address space of another process, use the <c>CreateRemoteThread</c> function.</para>
	/// </summary>
	/// <param name="lpThreadAttributes">
	/// <para>
	/// A pointer to a <c>SECURITY_ATTRIBUTES</c> structure that determines whether the returned handle can be inherited by child processes.
	/// If lpThreadAttributes is NULL, the handle cannot be inherited.
	/// </para>
	/// <para>
	/// The <c>lpSecurityDescriptor</c> member of the structure specifies a security descriptor for the new thread. If lpThreadAttributes is
	/// NULL, the thread gets a default security descriptor. The ACLs in the default security descriptor for a thread come from the primary
	/// token of the creator.
	/// </para>
	/// </param>
	/// <param name="dwStackSize">
	/// The initial size of the stack, in bytes. The system rounds this value to the nearest page. If this parameter is zero, the new thread
	/// uses the default size for the executable. For more information, see Thread Stack Size.
	/// </param>
	/// <param name="lpStartAddress">
	/// A pointer to the application-defined function to be executed by the thread. This pointer represents the starting address of the
	/// thread. For more information on the thread function, see <c>ThreadProc</c>.
	/// </param>
	/// <param name="lpParameter">A pointer to a variable to be passed to the thread.</param>
	/// <param name="dwCreationFlags">
	/// <para>The flags that control the creation of the thread.</para>
	/// <para>
	/// <list type="table">
	/// <listheader>
	/// <term>Value</term>
	/// <term>Meaning</term>
	/// </listheader>
	/// <item>
	/// <term>0</term>
	/// <term>The thread runs immediately after creation.</term>
	/// </item>
	/// <item>
	/// <term>CREATE_SUSPENDED0x00000004</term>
	/// <term>The thread is created in a suspended state, and does not run until the ResumeThread function is called.</term>
	/// </item>
	/// <item>
	/// <term>STACK_SIZE_PARAM_IS_A_RESERVATION0x00010000</term>
	/// <term>
	/// The dwStackSize parameter specifies the initial reserve size of the stack. If this flag is not specified, dwStackSize specifies the
	/// commit size.
	/// </term>
	/// </item>
	/// </list>
	/// </para>
	/// </param>
	/// <param name="lpThreadId">
	/// A pointer to a variable that receives the thread identifier. If this parameter is <c>NULL</c>, the thread identifier is not returned.
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is a handle to the new thread.</para>
	/// <para>If the function fails, the return value is <c>NULL</c>. To get extended error information, call <c>GetLastError</c>.</para>
	/// <para>
	/// Note that <c>CreateThread</c> may succeed even if lpStartAddress points to data, code, or is not accessible. If the start address is
	/// invalid when the thread runs, an exception occurs, and the thread terminates. Thread termination due to a invalid start address is
	/// handled as an error exit for the thread's process. This behavior is similar to the asynchronous nature of <c>CreateProcess</c>, where
	/// the process is created even if it refers to invalid or missing dynamic-link libraries (DLLs).
	/// </para>
	/// </returns>
	// HANDLE WINAPI CreateThread( _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, _In_ SIZE_T dwStackSize, _In_ LPTHREAD_START_ROUTINE
	// lpStartAddress, _In_opt_ LPVOID lpParameter, _In_ DWORD dwCreationFlags, _Out_opt_ LPDWORD lpThreadId); https://msdn.microsoft.com/en-us/library/windows/desktop/ms682453(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms682453")]
	[return: AddAsCtor]
	public static extern SafeHTHREAD CreateThread([In, Optional] SECURITY_ATTRIBUTES? lpThreadAttributes, [Optional] SizeT dwStackSize, ThreadProc lpStartAddress,
		[In, Optional] IntPtr lpParameter, [Optional] CREATE_THREAD_FLAGS dwCreationFlags, out uint lpThreadId);

	/// <summary>
	/// <para>Creates a thread to execute within the virtual address space of the calling process.</para>
	/// <para>To create a thread that runs in the virtual address space of another process, use the <c>CreateRemoteThread</c> function.</para>
	/// </summary>
	/// <param name="lpThreadAttributes">
	/// <para>
	/// A pointer to a <c>SECURITY_ATTRIBUTES</c> structure that determines whether the returned handle can be inherited by child processes.
	/// If lpThreadAttributes is NULL, the handle cannot be inherited.
	/// </para>
	/// <para>
	/// The <c>lpSecurityDescriptor</c> member of the structure specifies a security descriptor for the new thread. If lpThreadAttributes is
	/// NULL, the thread gets a default security descriptor. The ACLs in the default security descriptor for a thread come from the primary
	/// token of the creator.
	/// </para>
	/// </param>
	/// <param name="dwStackSize">
	/// The initial size of the stack, in bytes. The system rounds this value to the nearest page. If this parameter is zero, the new thread
	/// uses the default size for the executable. For more information, see Thread Stack Size.
	/// </param>
	/// <param name="lpStartAddress">
	/// A pointer to the application-defined function to be executed by the thread. This pointer represents the starting address of the
	/// thread. For more information on the thread function, see <c>ThreadProc</c>.
	/// </param>
	/// <param name="lpParameter">A pointer to a variable to be passed to the thread.</param>
	/// <param name="dwCreationFlags">
	/// <para>The flags that control the creation of the thread.</para>
	/// <para>
	/// <list type="table">
	/// <listheader>
	/// <term>Value</term>
	/// <term>Meaning</term>
	/// </listheader>
	/// <item>
	/// <term>0</term>
	/// <term>The thread runs immediately after creation.</term>
	/// </item>
	/// <item>
	/// <term>CREATE_SUSPENDED0x00000004</term>
	/// <term>The thread is created in a suspended state, and does not run until the ResumeThread function is called.</term>
	/// </item>
	/// <item>
	/// <term>STACK_SIZE_PARAM_IS_A_RESERVATION0x00010000</term>
	/// <term>
	/// The dwStackSize parameter specifies the initial reserve size of the stack. If this flag is not specified, dwStackSize specifies the
	/// commit size.
	/// </term>
	/// </item>
	/// </list>
	/// </para>
	/// </param>
	/// <param name="lpThreadId">
	/// A pointer to a variable that receives the thread identifier. If this parameter is <c>NULL</c>, the thread identifier is not returned.
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is a handle to the new thread.</para>
	/// <para>If the function fails, the return value is <c>NULL</c>. To get extended error information, call <c>GetLastError</c>.</para>
	/// <para>
	/// Note that <c>CreateThread</c> may succeed even if lpStartAddress points to data, code, or is not accessible. If the start address is
	/// invalid when the thread runs, an exception occurs, and the thread terminates. Thread termination due to a invalid start address is
	/// handled as an error exit for the thread's process. This behavior is similar to the asynchronous nature of <c>CreateProcess</c>, where
	/// the process is created even if it refers to invalid or missing dynamic-link libraries (DLLs).
	/// </para>
	/// </returns>
	// HANDLE WINAPI CreateThread( _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, _In_ SIZE_T dwStackSize, _In_ LPTHREAD_START_ROUTINE
	// lpStartAddress, _In_opt_ LPVOID lpParameter, _In_ DWORD dwCreationFlags, _Out_opt_ LPDWORD lpThreadId); https://msdn.microsoft.com/en-us/library/windows/desktop/ms682453(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms682453")]
	public static extern unsafe SafeHTHREAD CreateThread([In, Optional] SECURITY_ATTRIBUTES? lpThreadAttributes, [Optional] SizeT dwStackSize, ThreadProcUnsafe lpStartAddress,
		[In, Optional] void* lpParameter, [Optional] CREATE_THREAD_FLAGS dwCreationFlags, out uint lpThreadId);

	/// <summary>Deletes the specified list of attributes for process and thread creation.</summary>
	/// <param name="lpAttributeList">The attribute list. This list is created by the <see cref="InitializeProcThreadAttributeList"/>.</param>
	/// <returns>This function does not return a value.</returns>
	// VOID WINAPI DeleteProcThreadAttributeList( _Inout_ LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList); https://msdn.microsoft.com/en-us/library/windows/desktop/ms682559(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms682559")]
	public static extern void DeleteProcThreadAttributeList(IntPtr lpAttributeList);

	/// <summary>Ends the calling process and all its threads.</summary>
	/// <param name="uExitCode">The exit code for the process and all threads.</param>
	/// <returns>This function does not return a value.</returns>
	// VOID WINAPI ExitProcess( _In_ UINT uExitCode); https://msdn.microsoft.com/en-us/library/windows/desktop/ms682658(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms682658")]
	public static extern void ExitProcess(uint uExitCode);

	/// <summary>Ends the calling thread.</summary>
	/// <param name="dwExitCode">The exit code for the thread.</param>
	/// <returns>This function does not return a value.</returns>
	// VOID WINAPI ExitThread( _In_ DWORD dwExitCode); https://msdn.microsoft.com/en-us/library/windows/desktop/ms682659(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms682659")]
	public static extern void ExitThread(uint dwExitCode);

	/// <summary>Flushes the instruction cache for the specified process.</summary>
	/// <param name="hProcess">A handle to a process whose instruction cache is to be flushed.</param>
	/// <param name="lpBaseAddress">A pointer to the base of the region to be flushed. This parameter can be <c>NULL</c>.</param>
	/// <param name="dwSize">The size of the region to be flushed if the lpBaseAddress parameter is not <c>NULL</c>, in bytes.</param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// BOOL WINAPI FlushInstructionCache( _In_ HANDLE hProcess, _In_ LPCVOID lpBaseAddress, _In_ SIZE_T dwSize); https://msdn.microsoft.com/en-us/library/windows/desktop/ms679350(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms679350")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool FlushInstructionCache([In] HPROCESS hProcess, [In, Optional] IntPtr lpBaseAddress, [Optional] SizeT dwSize);

	/// <summary>Flushes the write queue of each processor that is running a thread of the current process.</summary>
	/// <returns>This function does not return a value.</returns>
	// VOID WINAPI FlushProcessWriteBuffers(void); https://msdn.microsoft.com/en-us/library/windows/desktop/ms683148(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms683148")]
	public static extern void FlushProcessWriteBuffers();

	/// <summary>Retrieves the process identifier of the calling process.</summary>
	/// <returns>The return value is the process identifier of the calling process.</returns>
	// DWORD WINAPI GetCurrentProcessId(void); https://msdn.microsoft.com/en-us/library/windows/desktop/ms683180(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms683180")]
	public static extern uint GetCurrentProcessId();

	/// <summary>
	/// <para>Retrieves the number of the processor the current thread was running on during the call to this function.</para>
	/// </summary>
	/// <returns>
	/// <para>The function returns the current processor number.</para>
	/// </returns>
	/// <remarks>
	/// <para>This function is used to provide information for estimating process performance.</para>
	/// <para>
	/// On systems with more than 64 logical processors, the <c>GetCurrentProcessorNumber</c> function returns the processor number within
	/// the processor group to which the logical processor is assigned. Use the GetCurrentProcessorNumberEx function to retrieve the
	/// processor group and number of the current processor.
	/// </para>
	/// </remarks>
	// https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-getcurrentprocessornumber DWORD
	// GetCurrentProcessorNumber( );
	[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
	[PInvokeData("processthreadsapi.h", MSDNShortId = "1f2bebc7-a548-409a-ab74-78a4b55c8fa7")]
	public static extern uint GetCurrentProcessorNumber();

	/// <summary>Retrieves the processor group and number of the logical processor in which the calling thread is running.</summary>
	/// <param name="ProcNumber">
	/// A pointer to a <c>PROCESSOR_NUMBER</c> structure that receives the processor group to which the logical processor is assigned and the
	/// number of the logical processor within its group.
	/// </param>
	/// <returns>
	/// If the function succeeds, the ProcNumber parameter contains the group and processor number of the processor on which the calling
	/// thread is running.
	/// </returns>
	// VOID GetCurrentProcessorNumberEx( _Out_ PPROCESSOR_NUMBER ProcNumber); https://msdn.microsoft.com/en-us/library/windows/desktop/dd405487(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "dd405487")]
	public static extern void GetCurrentProcessorNumberEx(out PROCESSOR_NUMBER ProcNumber);

	/// <summary>Retrieves a pseudo-handle that you can use as a shorthand way to refer to the access token associated with a process.</summary>
	/// <returns>A pseudo-handle that you can use as a shorthand way to refer to the access token associated with a process.</returns>
	[PInvokeData("Processthreadsapi.h", MSDNShortId = "mt643211")]
	public static HTOKEN GetCurrentProcessToken() => new IntPtr(-4);

	/// <summary>Retrieves a pseudo handle for the calling thread.</summary>
	/// <returns>The return value is a pseudo handle for the current thread.</returns>
	/// <remarks>
	/// A pseudo handle is a special constant that is interpreted as the current thread handle. The calling thread can use this handle to
	/// specify itself whenever a thread handle is required. Pseudo handles are not inherited by child processes.
	/// <para>
	/// This handle has the THREAD_ALL_ACCESS access right to the thread object. For more information, see Thread Security and Access Rights.
	/// </para>
	/// <para>
	/// Windows Server 2003 and Windows XP: This handle has the maximum access allowed by the security descriptor of the thread to the
	/// primary token of the process.
	/// </para>
	/// <para>
	/// The function cannot be used by one thread to create a handle that can be used by other threads to refer to the first thread. The
	/// handle is always interpreted as referring to the thread that is using it. A thread can create a "real" handle to itself that can be
	/// used by other threads, or inherited by other processes, by specifying the pseudo handle as the source handle in a call to the
	/// DuplicateHandle function.
	/// </para>
	/// <para>
	/// The pseudo handle need not be closed when it is no longer needed. Calling the CloseHandle function with this handle has no effect. If
	/// the pseudo handle is duplicated by DuplicateHandle, the duplicate handle must be closed.
	/// </para>
	/// <para>
	/// Do not create a thread while impersonating a security context. The call will succeed, however the newly created thread will have
	/// reduced access rights to itself when calling GetCurrentThread. The access rights granted this thread will be derived from the access
	/// rights the impersonated user has to the process. Some access rights including THREAD_SET_THREAD_TOKEN and THREAD_GET_CONTEXT may not
	/// be present, leading to unexpected failures.
	/// </para>
	/// </remarks>
	[DllImport(Lib.Kernel32, ExactSpelling = true, SetLastError = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms683182")]
	public static extern HTHREAD GetCurrentThread();

	/// <summary>
	/// Retrieves a pseudo-handle that you can use as a shorthand way to refer to the token that is currently in effect for the thread, which
	/// is the thread token if one exists and the process token otherwise.
	/// </summary>
	/// <returns>A pseudo-handle that you can use as a shorthand way to refer to the token that is currently in effect for the thread.</returns>
	// FORCEINLINE HANDLE GetCurrentThreadEffectiveToken(void); https://msdn.microsoft.com/en-us/library/windows/desktop/mt643212(v=vs.85).aspx
	[PInvokeData("Processthreadsapi.h", MSDNShortId = "mt643212")]
	public static HTOKEN GetCurrentThreadEffectiveToken() => new IntPtr(-6);

	/// <summary>Retrieves the thread identifier of the calling thread.</summary>
	/// <returns>The return value is the thread identifier of the calling thread.</returns>
	// DWORD WINAPI GetCurrentThreadId(void); https://msdn.microsoft.com/en-us/library/windows/desktop/ms683183(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms683183")]
	public static extern uint GetCurrentThreadId();

	/// <summary>Retrieves the boundaries of the stack that was allocated by the system for the current thread.</summary>
	/// <param name="LowLimit">A pointer variable that receives the lower boundary of the current thread stack.</param>
	/// <param name="HighLimit">A pointer variable that receives the upper boundary of the current thread stack.</param>
	/// <returns>This function does not return a value.</returns>
	// VOID WINAPI GetCurrentThreadStackLimits( _Out_ PULONG_PTR LowLimit, _Out_ PULONG_PTR HighLimit); https://msdn.microsoft.com/en-us/library/windows/desktop/hh706789(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
	[PInvokeData("Processthreadsapi.h", MSDNShortId = "hh706789")]
	public static extern void GetCurrentThreadStackLimits(out nuint LowLimit, out nuint HighLimit);

	/// <summary>
	/// Retrieves a pseudo-handle that you can use as a shorthand way to refer to the impersonation token that was assigned to the current thread.
	/// </summary>
	/// <returns>
	/// A pseudo-handle that you can use as a shorthand way to refer to the impersonation token that was assigned to the current thread.
	/// </returns>
	// FORCEINLINE HANDLE GetCurrentThreadEffectiveToken(void); https://msdn.microsoft.com/en-us/library/windows/desktop/mt643213(v=vs.85).aspx
	[PInvokeData("Processthreadsapi.h", MSDNShortId = "mt643213")]
	public static HTOKEN GetCurrentThreadToken() => new IntPtr(-5);

	/// <summary>Retrieves the termination status of the specified process.</summary>
	/// <param name="hProcess">
	/// <para>A handle to the process.</para>
	/// <para>
	/// The handle must have the <c>PROCESS_QUERY_INFORMATION</c> or <c>PROCESS_QUERY_LIMITED_INFORMATION</c> access right. For more
	/// information, see Process Security and Access Rights.
	/// </para>
	/// <para><c>Windows Server 2003 and Windows XP:</c> The handle must have the <c>PROCESS_QUERY_INFORMATION</c> access right.</para>
	/// </param>
	/// <param name="lpExitCode">A pointer to a variable to receive the process termination status. For more information, see Remarks.</param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// BOOL WINAPI GetExitCodeProcess( _In_ HANDLE hProcess, _Out_ LPDWORD lpExitCode); https://msdn.microsoft.com/en-us/library/windows/desktop/ms683189(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms683189")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool GetExitCodeProcess([In, AddAsMember] HPROCESS hProcess, out uint lpExitCode);

	/// <summary>Retrieves the termination status of the specified thread.</summary>
	/// <param name="hThread">
	/// <para>A handle to the thread.</para>
	/// <para>
	/// The handle must have the <c>THREAD_QUERY_INFORMATION</c> or <c>THREAD_QUERY_LIMITED_INFORMATION</c> access right. For more
	/// information, see Thread Security and Access Rights.
	/// </para>
	/// <para><c>Windows Server 2003 and Windows XP:</c> The handle must have the <c>THREAD_QUERY_INFORMATION</c> access right.</para>
	/// </param>
	/// <param name="lpExitCode">A pointer to a variable to receive the thread termination status. For more information, see Remarks.</param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// BOOL WINAPI GetExitCodeThread( _In_ HANDLE hThread, _Out_ LPDWORD lpExitCode); https://msdn.microsoft.com/en-us/library/windows/desktop/ms683190(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms683190")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool GetExitCodeThread([In, AddAsMember] HTHREAD hThread, out uint lpExitCode);

	/// <summary>
	/// Queries if the specified architecture is supported on the current system, either natively or by any form of compatibility or
	/// emulation layer.
	/// </summary>
	/// <param name="Machine">
	/// An IMAGE_FILE_MACHINE_* value corresponding to the architecture of code to be tested for supportability. See the list of architecture
	/// values in Image File Machine Constants.
	/// </param>
	/// <param name="MachineTypeAttributes">
	/// Output parameter receives a pointer to a value from the MACHINE_ATTRIBUTES enumeration indicating if the specified code architecture
	/// can run in user mode, kernel mode, and/or under WOW64 on the host operating system.
	/// </param>
	/// <returns>If the function fails, the return value is a nonzero HRESULT value. If the function succeeds, the return value is zero.</returns>
	// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getmachinetypeattributes HRESULT
	// GetMachineTypeAttributes( USHORT Machine, MACHINE_ATTRIBUTES *MachineTypeAttributes );
	[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
	[PInvokeData("processthreadsapi.h", MSDNShortId = "NF:processthreadsapi.GetMachineTypeAttributes")]
	public static extern HRESULT GetMachineTypeAttributes(IMAGE_FILE_MACHINE Machine, out MACHINE_ATTRIBUTES MachineTypeAttributes);

	/// <summary>
	/// Retrieves the priority class for the specified process. This value, together with the priority value of each thread of the process,
	/// determines each thread's base priority level.
	/// </summary>
	/// <param name="hProcess">
	/// <para>A handle to the process.</para>
	/// <para>
	/// The handle must have the <c>PROCESS_QUERY_INFORMATION</c> or <c>PROCESS_QUERY_LIMITED_INFORMATION</c> access right. For more
	/// information, see Process Security and Access Rights.
	/// </para>
	/// <para><c>Windows Server 2003 and Windows XP:</c> The handle must have the <c>PROCESS_QUERY_INFORMATION</c> access right.</para>
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is the priority class of the specified process.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
	/// <para>The process's priority class is one of the following values.</para>
	/// <para>
	/// <list type="table">
	/// <listheader>
	/// <term>Return code/value</term>
	/// <term>Description</term>
	/// </listheader>
	/// <item>
	/// <term>ABOVE_NORMAL_PRIORITY_CLASS0x00008000</term>
	/// <term>Process that has priority above NORMAL_PRIORITY_CLASS but below HIGH_PRIORITY_CLASS.</term>
	/// </item>
	/// <item>
	/// <term>BELOW_NORMAL_PRIORITY_CLASS0x00004000</term>
	/// <term>Process that has priority above IDLE_PRIORITY_CLASS but below NORMAL_PRIORITY_CLASS.</term>
	/// </item>
	/// <item>
	/// <term>HIGH_PRIORITY_CLASS0x00000080</term>
	/// <term>
	/// Process that performs time-critical tasks that must be executed immediately for it to run correctly. The threads of a high-priority
	/// class process preempt the threads of normal or idle priority class processes. An example is the Task List, which must respond quickly
	/// when called by the user, regardless of the load on the operating system. Use extreme care when using the high-priority class, because
	/// a high-priority class CPU-bound application can use nearly all available cycles.
	/// </term>
	/// </item>
	/// <item>
	/// <term>IDLE_PRIORITY_CLASS0x00000040</term>
	/// <term>
	/// Process whose threads run only when the system is idle and are preempted by the threads of any process running in a higher priority
	/// class. An example is a screen saver. The idle priority class is inherited by child processes.
	/// </term>
	/// </item>
	/// <item>
	/// <term>NORMAL_PRIORITY_CLASS0x00000020</term>
	/// <term>Process with no special scheduling needs.</term>
	/// </item>
	/// <item>
	/// <term>REALTIME_PRIORITY_CLASS0x00000100</term>
	/// <term>
	/// Process that has the highest possible priority. The threads of a real-time priority class process preempt the threads of all other
	/// processes, including operating system processes performing important tasks. For example, a real-time process that executes for more
	/// than a very brief interval can cause disk caches not to flush or cause the mouse to be unresponsive.
	/// </term>
	/// </item>
	/// </list>
	/// </para>
	/// </returns>
	// DWORD WINAPI GetPriorityClass( _In_ HANDLE hProcess); https://msdn.microsoft.com/en-us/library/windows/desktop/ms683211(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms683211")]
	public static extern CREATE_PROCESS GetPriorityClass([In, AddAsMember] HPROCESS hProcess);

	/// <summary>Retrieves the list of CPU Sets in the process default set that was set by SetProcessDefaultCpuSetMasks or SetProcessDefaultCpuSets.</summary>
	/// <param name="Process">
	/// Specifies a process handle for the process to query. This handle must have the PROCESS_QUERY_LIMITED_INFORMATION access right. The
	/// value returned by GetCurrentProcess can also be specified here.
	/// </param>
	/// <param name="CpuSetMasks">
	/// Specifies an optional buffer to retrieve a list of GROUP_AFFINITY structures representing the process default CPU Sets.
	/// </param>
	/// <param name="CpuSetMaskCount">Specifies the size of the CpuSetMasks array, in elements.</param>
	/// <param name="RequiredMaskCount">
	/// On successful return, specifies the number of affinity structures written to the array. If the CpuSetMasks array is too small, the
	/// function fails with <c>ERROR_INSUFFICIENT_BUFFER</c> and sets the RequiredMaskCount parameter to the number of elements required. The
	/// number of required elements is always less than or equal to the maximum group count returned by GetMaximumProcessorGroupCount.
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero and extended error information can be retrieved by calling GetLastError.</para>
	/// <para>
	/// If the array supplied is too small, the error value is <c>ERROR_INSUFFICIENT_BUFFER</c> and the RequiredMaskCount is set to the
	/// number of elements required.
	/// </para>
	/// </returns>
	/// <remarks>
	/// <para>If no default CPU Sets are set for a given process, then the RequiredMaskCount parameter is set to 0 and the function succeeds.</para>
	/// <para>
	/// This function is analogous to GetProcessDefaultCpuSets, except that it uses group affinities as opposed to CPU Set IDs to represent a
	/// list of CPU sets. This means that the process default CPU Sets are mapped to their home processors, and those processors are
	/// retrieved in the resulting list of group affinities.
	/// </para>
	/// </remarks>
	// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getprocessdefaultcpusetmasks BOOL
	// GetProcessDefaultCpuSetMasks( HANDLE Process, PGROUP_AFFINITY CpuSetMasks, USHORT CpuSetMaskCount, PUSHORT RequiredMaskCount );
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("processthreadsapi.h", MSDNShortId = "NF:processthreadsapi.GetProcessDefaultCpuSetMasks")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool GetProcessDefaultCpuSetMasks([In, AddAsMember] HPROCESS Process,
		[Out, Optional, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2),
		SizeDef(nameof(CpuSetMaskCount), SizingMethod.Query | SizingMethod.CheckLastError, OutVarName = nameof(RequiredMaskCount))] GROUP_AFFINITY[]? CpuSetMasks,
		ushort CpuSetMaskCount, out ushort RequiredMaskCount);

	/// <summary>
	/// Retrieves the list of CPU Sets in the process default set that was set by <c>SetProcessDefaultCpuSets</c>. If no default CPU Sets are
	/// set for a given process, then the <c>RequiredIdCount</c> is set to 0 and the function succeeds.
	/// </summary>
	/// <param name="Process">
	/// Specifies a process handle for the process to query. This handle must have the PROCESS_QUERY_LIMITED_INFORMATION access right. The
	/// value returned by <c>GetCurrentProcess</c> can also be specified here.
	/// </param>
	/// <param name="CpuSetIds">Specifies an optional buffer to retrieve the list of CPU Set identifiers.</param>
	/// <param name="CpuSetIdCount">
	/// Specifies the capacity of the buffer specified in <c>CpuSetIds</c>. If the buffer is NULL, this must be 0.
	/// </param>
	/// <param name="RequiredIdCount">
	/// Specifies the required capacity of the buffer to hold the entire list of process default CPU Sets. On successful return, this
	/// specifies the number of IDs filled into the buffer.
	/// </param>
	/// <returns>
	/// This API returns TRUE on success. If the buffer is not large enough the API returns FALSE, and the <c>GetLastError</c> value is
	/// ERROR_INSUFFICIENT_BUFFER. This API cannot fail when passed valid parameters and the return buffer is large enough.
	/// </returns>
	// BOOL WINAPI GetProcessDefaultCpuSets( _In_ HANDLE Process, _Out_opt_ PULONG CpuSetIds, _In_ ULONG CpuSetIdCount, _Out_ PULONG
	// RequiredIdCount); https://msdn.microsoft.com/en-us/library/windows/desktop/mt186424(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("Processthreadapi.h", MSDNShortId = "mt186424")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool GetProcessDefaultCpuSets(HPROCESS Process, IntPtr CpuSetIds, uint CpuSetIdCount, out uint RequiredIdCount);

	/// <summary>
	/// Retrieves the list of CPU Sets in the process default set that was set by <c>SetProcessDefaultCpuSets</c>. If no default CPU Sets are
	/// set for a given process, then an empty array is returned.
	/// </summary>
	/// <param name="Process">
	/// Specifies a process handle for the process to query. This handle must have the PROCESS_QUERY_LIMITED_INFORMATION access right. The
	/// value returned by <c>GetCurrentProcess</c> can also be specified here.
	/// </param>
	/// <returns>The list of CPU Set identifiers.</returns>
	public static uint[] GetProcessDefaultCpuSets([In, AddAsMember] HPROCESS Process)
	{
		uint cnt = (uint)Environment.ProcessorCount;
		if (cnt == 0) return [];
		SafeCoTaskMemHandle iptr = new((int)cnt * Marshal.SizeOf<uint>());
		if (!GetProcessDefaultCpuSets(Process, (IntPtr)iptr, cnt, out cnt)) Win32Error.ThrowLastError();
		return iptr.ToArray<uint>((int)cnt);
	}

	/// <summary>Retrieves the number of open handles that belong to the specified process.</summary>
	/// <param name="hProcess">
	/// <para>
	/// A handle to the process whose handle count is being requested. The handle must have the PROCESS_QUERY_INFORMATION or
	/// PROCESS_QUERY_LIMITED_INFORMATION access right. For more information, see Process Security and Access Rights.
	/// </para>
	/// <para><c>Windows Server 2003 and Windows XP:</c> The handle must have the PROCESS_QUERY_INFORMATION access right.</para>
	/// </param>
	/// <param name="pdwHandleCount">A pointer to a variable that receives the number of open handles that belong to the specified process.</param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// BOOL WINAPI GetProcessHandleCount( _In_ HANDLE hProcess, _Inout_ PDWORD pdwHandleCount); https://msdn.microsoft.com/en-us/library/windows/desktop/ms683214(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms683214")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool GetProcessHandleCount([In, AddAsMember] HPROCESS hProcess, out uint pdwHandleCount);

	/// <summary>Retrieves the process identifier of the specified process.</summary>
	/// <param name="Process">
	/// <para>
	/// A handle to the process. The handle must have the PROCESS_QUERY_INFORMATION or PROCESS_QUERY_LIMITED_INFORMATION access right. For
	/// more information, see Process Security and Access Rights.
	/// </para>
	/// <para><c>Windows Server 2003 and Windows XP:</c> The handle must have the PROCESS_QUERY_INFORMATION access right.</para>
	/// </param>
	/// <returns></returns>
	// DWORD WINAPI GetProcessId( _In_ HANDLE Process); https://msdn.microsoft.com/en-us/library/windows/desktop/ms683215(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms683215")]
	public static extern uint GetProcessId([In, AddAsMember] HPROCESS Process);

	/// <summary>Retrieves the process identifier of the process associated with the specified thread.</summary>
	/// <param name="Thread">
	/// <para>
	/// A handle to the thread. The handle must have the THREAD_QUERY_INFORMATION or THREAD_QUERY_LIMITED_INFORMATION access right. For more
	/// information, see Thread Security and Access Rights.
	/// </para>
	/// <para><c>Windows Server 2003:</c> The handle must have the THREAD_QUERY_INFORMATION access right.</para>
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is the process identifier of the process associated with the specified thread.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// DWORD WINAPI GetProcessIdOfThread( _In_ HANDLE Thread); https://msdn.microsoft.com/en-us/library/windows/desktop/ms683216(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms683216")]
	public static extern uint GetProcessIdOfThread([In, AddAsMember] HTHREAD Thread);

	/// <summary>Retrieves information about the specified process.</summary>
	/// <param name="hProcess">
	/// A handle to the process. This handle must have the <c>PROCESS_SET_INFORMATION</c> access right. For more information, see Process
	/// Security and Access Rights.
	/// </param>
	/// <param name="ProcessInformationClass">
	/// A member of the PROCESS_INFORMATION_CLASS enumeration specifying the kind of information to retrieve.
	/// </param>
	/// <param name="ProcessInformation">
	/// <para>Pointer to an object to receive the type of information specified by the ProcessInformationClass parameter.</para>
	/// <para>
	/// If the ProcessInformationClass parameter is <c>ProcessMemoryPriority</c>, this parameter must point to a MEMORY_PRIORITY_INFORMATION structure.
	/// </para>
	/// <para>
	/// If the ProcessInformationClass parameter is <c>ProcessPowerThrottling</c>, this parameter must point to a
	/// PROCESS_POWER_THROTTLING_STATE structure.
	/// </para>
	/// <para>
	/// If the ProcessInformationClass parameter is <c>ProcessProtectionLevelInfo</c>, this parameter must point to a
	/// PROCESS_PROTECTION_LEVEL_INFORMATION structure.
	/// </para>
	/// <para>
	/// If the ProcessInformationClass parameter is <c>ProcessLeapSecondInfo</c>, this parameter must point to a PROCESS_LEAP_SECOND_INFO structure.
	/// </para>
	/// <para>
	/// If the ProcessInformationClass parameter is <c>ProcessAppMemoryInfo</c>, this parameter must point to a APP_MEMORY_INFORMATION structure.
	/// </para>
	/// </param>
	/// <param name="ProcessInformationSize">
	/// <para>The size in bytes of the structure specified by the ProcessInformation parameter.</para>
	/// <para>If the ProcessInformationClass parameter is <c>ProcessMemoryPriority</c>, this parameter must be
	/// <code>sizeof(MEMORY_PRIORITY_INFORMATION)</code>
	/// .
	/// </para>
	/// <para>If the ProcessInformationClass parameter is <c>ProcessPowerThrottling</c>, this parameter must be
	/// <code>sizeof(PROCESS_POWER_THROTTLING_STATE)</code>
	/// .
	/// </para>
	/// <para>If the ProcessInformationClass parameter is <c>ProcessProtectionLevelInfo</c>, this parameter must be
	/// <code>sizeof(PROCESS_PROTECTION_LEVEL_INFORMATION)</code>
	/// .
	/// </para>
	/// <para>If the ProcessInformationClass parameter is <c>ProcessLeapSecondInfo</c>, this parameter must be
	/// <code>sizeof(PROCESS_LEAP_SECOND_INFO)</code>
	/// .
	/// </para>
	/// <para>If the ProcessInformationClass parameter is <c>ProcessAppMemoryInfo</c>, this parameter must be
	/// <code>sizeof(APP_MEMORY_INFORMATION)</code>
	/// .
	/// </para>
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call GetLastError.</para>
	/// </returns>
	// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getprocessinformation BOOL
	// GetProcessInformation( HANDLE hProcess, PROCESS_INFORMATION_CLASS ProcessInformationClass, LPVOID ProcessInformation, DWORD
	// ProcessInformationSize );
	[PInvokeData("processthreadsapi.h", MSDNShortId = "NF:processthreadsapi.GetProcessInformation")]
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool GetProcessInformation(HPROCESS hProcess, PROCESS_INFORMATION_CLASS ProcessInformationClass,
		IntPtr ProcessInformation, uint ProcessInformationSize);

	/// <summary>Retrieves information about the specified process.</summary>
	/// <typeparam name="T">The type to retrive.</typeparam>
	/// <param name="hProcess">
	/// A handle to the process. This handle must have the <c>PROCESS_SET_INFORMATION</c> access right. For more information, see Process
	/// Security and Access Rights.
	/// </param>
	/// <param name="ProcessInformationClass">
	/// A member of the PROCESS_INFORMATION_CLASS enumeration specifying the kind of information to retrieve.
	/// </param>
	/// <returns>
	/// <para>Pointer to an object to receive the type of information specified by the ProcessInformationClass parameter.</para>
	/// <para>
	/// If the ProcessInformationClass parameter is <c>ProcessMemoryPriority</c>, this parameter must point to a MEMORY_PRIORITY_INFORMATION structure.
	/// </para>
	/// <para>
	/// If the ProcessInformationClass parameter is <c>ProcessPowerThrottling</c>, this parameter must point to a
	/// PROCESS_POWER_THROTTLING_STATE structure.
	/// </para>
	/// <para>
	/// If the ProcessInformationClass parameter is <c>ProcessProtectionLevelInfo</c>, this parameter must point to a
	/// PROCESS_PROTECTION_LEVEL_INFORMATION structure.
	/// </para>
	/// <para>
	/// If the ProcessInformationClass parameter is <c>ProcessLeapSecondInfo</c>, this parameter must point to a PROCESS_LEAP_SECOND_INFO structure.
	/// </para>
	/// <para>
	/// If the ProcessInformationClass parameter is <c>ProcessAppMemoryInfo</c>, this parameter must point to a APP_MEMORY_INFORMATION structure.
	/// </para>
	/// </returns>
	public static T GetProcessInformation<T>([In, AddAsMember] HPROCESS hProcess, PROCESS_INFORMATION_CLASS ProcessInformationClass = (PROCESS_INFORMATION_CLASS)(-1)) where T : struct
	{
		if (!ProcessInformationClass.IsValid() && !CorrespondingTypeAttribute.CanGet<T, PROCESS_INFORMATION_CLASS>(out ProcessInformationClass))
			throw new ArgumentException("The type specified by the type parameter cannot be retrieved for a process.", nameof(T));
		else if (!CorrespondingTypeAttribute.CanGet(ProcessInformationClass, typeof(T)))
			throw new ArgumentException("Type mismatch.");
		using SafeCoTaskMemStruct<T> mem = new();
		if (!GetProcessInformation(hProcess, ProcessInformationClass, mem, mem.Size))
			Win32Error.ThrowLastError();
		return mem.Value;
	}

	/// <summary>Retrieves mitigation policy settings for the calling process.</summary>
	/// <param name="hProcess">
	/// A handle to the process. This handle must have the PROCESS_QUERY_INFORMATION access right. For more information, see Process Security
	/// and Access Rights.
	/// </param>
	/// <param name="MitigationPolicy">
	/// <para>The mitigation policy to retrieve. This parameter can be one of the following values.</para>
	/// <para>
	/// <list type="table">
	/// <listheader>
	/// <term>Value</term>
	/// <term>Meaning</term>
	/// </listheader>
	/// <item>
	/// <term>ProcessDEPPolicy</term>
	/// <term>
	/// The data execution prevention (DEP) policy of the process.The lpBuffer parameter points to a PROCESS_MITIGATION_DEP_POLICY structure
	/// that specifies the DEP policy flags.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessASLRPolicy</term>
	/// <term>
	/// The Address Space Layout Randomization (ASLR) policy of the process.The lpBuffer parameter points to a PROCESS_MITIGATION_ASLR_POLICY
	/// structure that specifies the ASLR policy flags.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessDynamicCodePolicy</term>
	/// <term>
	/// The dynamic code policy of the process. When turned on, the process cannot generate dynamic code or modify existing executable
	/// code.The lpBuffer parameter points to a PROCESS_MITIGATION_DYNAMIC_CODE_POLICY structure that specifies the dynamic code policy flags.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessStrictHandleCheckPolicy</term>
	/// <term>
	/// The process will receive a fatal error if it manipulates a handle that is not valid.The lpBuffer parameter points to a
	/// PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY structure that specifies the handle check policy flags.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessSystemCallDisablePolicy</term>
	/// <term>
	/// Disables the ability to use NTUser/GDI functions at the lowest layer.The lpBuffer parameter points to a
	/// PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY structure that specifies the system call disable policy flags.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessMitigationOptionsMask</term>
	/// <term>
	/// Returns the mask of valid bits for all the mitigation options on the system. An application can set many mitigation options without
	/// querying the operating system for mitigation options by combining bitwise with the mask to exclude all non-supported bits at once.The
	/// lpBuffer parameter points to a ULONG64 bit vector for the mask, or a two-element array of ULONG64 bit vectors.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessExtensionPointDisablePolicy</term>
	/// <term>
	/// Prevents certain built-in third party extension points from being enabled, preventing legacy extension point DLLs from being loaded
	/// into the process.The lpBuffer parameter points to a PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY structure that specifies the
	/// extension point disable policy flags.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessControlFlowGuardPolicy</term>
	/// <term>
	/// The Control Flow Guard (CFG) policy of the process.The lpBuffer parameter points to a PROCESS_MITIGATION_CONTROL_FLOW_GUARD_POLICY
	/// structure that specifies the CFG policy flags.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessSignaturePolicy</term>
	/// <term>
	/// The policy of a process that can restrict image loading to those images that are either signed by Microsoft, by the Windows Store, or
	/// by Microsoft, the Windows Store and the Windows Hardware Quality Labs (WHQL).he lpBuffer parameter points to a
	/// PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY structure that specifies the signature policy flags.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessFontDisablePolicy</term>
	/// <term>
	/// The policy regarding font loading for the process. When turned on, the process cannot load non-system fonts.The lpBuffer parameter
	/// points to a PROCESS_MITIGATION_FONT_DISABLE_POLICY structure that specifies the policy flags for font loading.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessImageLoadPolicy</term>
	/// <term>
	/// The policy regarding image loading for the process, which determines the types of executable images that are allowed to be mapped
	/// into the process. When turned on, images cannot be loaded from some locations, such a remote devices or files that have the low
	/// mandatory label.The lpBuffer parameter points to a PROCESS_MITIGATION_IMAGE_LOAD_POLICY structure that specifies the policy flags for
	/// image loading.
	/// </term>
	/// </item>
	/// </list>
	/// </para>
	/// </param>
	/// <param name="lpBuffer">
	/// <para>
	/// If the MitigationPolicy parameter is <c>ProcessDEPPolicy</c>, this parameter points to a <c>PROCESS_MITIGATION_DEP_POLICY</c>
	/// structure that receives the DEP policy flags.
	/// </para>
	/// <para>
	/// If the MitigationPolicy parameter is <c>ProcessASLRPolicy</c>, this parameter points to a <c>PROCESS_MITIGATION_ASLR_POLICY</c>
	/// structure that receives the ASLR policy flags.
	/// </para>
	/// <para>
	/// If the MitigationPolicy parameter is <c>ProcessDynamicCodePolicy</c>, this parameter points to a
	/// <c>PROCESS_MITIGATION_DYNAMIC_CODE_POLICY</c> structure that receives the dynamic code policy flags.
	/// </para>
	/// <para>
	/// If the MitigationPolicy parameter is <c>ProcessStrictHandleCheckPolicy</c>, this parameter points to a
	/// <c>PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY</c> structure that specifies the handle check policy flags.
	/// </para>
	/// <para>
	/// If the MitigationPolicy parameter is <c>ProcessSystemCallDisablePolicy</c>, this parameter points to a
	/// <c>PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY</c> structure that specifies the system call disable policy flags.
	/// </para>
	/// <para>
	/// If the MitigationPolicy parameter is <c>ProcessMitigationOptionsMask</c>, this parameter points to a <c>ULONG64</c> bit vector for
	/// the mask or a two-element array of <c>ULONG64</c> bit vectors.
	/// </para>
	/// <para>
	/// If the MitigationPolicy parameter is <c>ProcessExtensionPointDisablePolicy</c>, this parameter points to a
	/// <c>PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY</c> structure that specifies the extension point disable policy flags.
	/// </para>
	/// <para>
	/// If the MitigationPolicy parameter is <c>ProcessControlFlowGuardPolicy</c>, this parameter points to a
	/// <c>PROCESS_MITIGATION_CONTROL_FLOW_GUARD_POLICY</c> structure that specifies the CFG policy flags.
	/// </para>
	/// <para>
	/// If the MitigationPolicy parameter is <c>ProcessSignaturePolicy</c>, this parameter points to a
	/// <c>PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY</c> structure that receives the signature policy flags.
	/// </para>
	/// <para>
	/// If the MitigationPolicy parameter is <c>ProcessFontDisablePolicy</c>, this parameter points to a
	/// <c>PROCESS_MITIGATION_FONT_DISABLE_POLICY</c> structure that receives the policy flags for font loading.
	/// </para>
	/// <para>
	/// If the MitigationPolicy parameter is <c>ProcessImageLoadPolicy</c>, this parameter points to a
	/// <c>PROCESS_MITIGATION_IMAGE_LOAD_POLICY</c> structure that receives the policy flags for image loading.
	/// </para>
	/// </param>
	/// <param name="dwLength">The size of lpBuffer, in bytes.</param>
	/// <returns>
	/// If the function succeeds, it returns <c>TRUE</c>. If the function fails, it returns <c>FALSE</c>. To retrieve error values defined
	/// for this function, call <c>GetLastError</c>.
	/// </returns>
	// BOOL WINAPI GetProcessMitigationPolicy( _In_ HANDLE hProcess, _In_ PROCESS_MITIGATION_POLICY MitigationPolicy, _Out_ PVOID lpBuffer,
	// _In_ SIZE_T dwLength); https://msdn.microsoft.com/en-us/library/windows/desktop/hh769085(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("Processthreadsapi.h", MSDNShortId = "hh769085")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool GetProcessMitigationPolicy(HPROCESS hProcess, PROCESS_MITIGATION_POLICY MitigationPolicy, IntPtr lpBuffer, SizeT dwLength);

	/// <summary>Retrieves mitigation policy settings for the calling process.</summary>
	/// <typeparam name="T">The type of the value to retrieve.</typeparam>
	/// <param name="hProcess">
	/// A handle to the process. This handle must have the PROCESS_QUERY_INFORMATION access right. For more information, see Process Security
	/// and Access Rights.
	/// </param>
	/// <param name="MitigationPolicy">
	/// <para>The mitigation policy to retrieve. This parameter can be one of the following values.</para>
	/// <para>
	/// <list type="table">
	/// <listheader>
	/// <term>Value</term>
	/// <term>Meaning</term>
	/// </listheader>
	/// <item>
	/// <term>ProcessDEPPolicy</term>
	/// <term>
	/// The data execution prevention (DEP) policy of the process.The lpBuffer parameter points to a PROCESS_MITIGATION_DEP_POLICY structure
	/// that specifies the DEP policy flags.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessASLRPolicy</term>
	/// <term>
	/// The Address Space Layout Randomization (ASLR) policy of the process.The lpBuffer parameter points to a PROCESS_MITIGATION_ASLR_POLICY
	/// structure that specifies the ASLR policy flags.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessDynamicCodePolicy</term>
	/// <term>
	/// The dynamic code policy of the process. When turned on, the process cannot generate dynamic code or modify existing executable
	/// code.The lpBuffer parameter points to a PROCESS_MITIGATION_DYNAMIC_CODE_POLICY structure that specifies the dynamic code policy flags.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessStrictHandleCheckPolicy</term>
	/// <term>
	/// The process will receive a fatal error if it manipulates a handle that is not valid.The lpBuffer parameter points to a
	/// PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY structure that specifies the handle check policy flags.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessSystemCallDisablePolicy</term>
	/// <term>
	/// Disables the ability to use NTUser/GDI functions at the lowest layer.The lpBuffer parameter points to a
	/// PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY structure that specifies the system call disable policy flags.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessMitigationOptionsMask</term>
	/// <term>
	/// Returns the mask of valid bits for all the mitigation options on the system. An application can set many mitigation options without
	/// querying the operating system for mitigation options by combining bitwise with the mask to exclude all non-supported bits at once.The
	/// lpBuffer parameter points to a ULONG64 bit vector for the mask, or a two-element array of ULONG64 bit vectors.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessExtensionPointDisablePolicy</term>
	/// <term>
	/// Prevents certain built-in third party extension points from being enabled, preventing legacy extension point DLLs from being loaded
	/// into the process.The lpBuffer parameter points to a PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY structure that specifies the
	/// extension point disable policy flags.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessControlFlowGuardPolicy</term>
	/// <term>
	/// The Control Flow Guard (CFG) policy of the process.The lpBuffer parameter points to a PROCESS_MITIGATION_CONTROL_FLOW_GUARD_POLICY
	/// structure that specifies the CFG policy flags.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessSignaturePolicy</term>
	/// <term>
	/// The policy of a process that can restrict image loading to those images that are either signed by Microsoft, by the Windows Store, or
	/// by Microsoft, the Windows Store and the Windows Hardware Quality Labs (WHQL).he lpBuffer parameter points to a
	/// PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY structure that specifies the signature policy flags.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessFontDisablePolicy</term>
	/// <term>
	/// The policy regarding font loading for the process. When turned on, the process cannot load non-system fonts.The lpBuffer parameter
	/// points to a PROCESS_MITIGATION_FONT_DISABLE_POLICY structure that specifies the policy flags for font loading.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessImageLoadPolicy</term>
	/// <term>
	/// The policy regarding image loading for the process, which determines the types of executable images that are allowed to be mapped
	/// into the process. When turned on, images cannot be loaded from some locations, such a remote devices or files that have the low
	/// mandatory label.The lpBuffer parameter points to a PROCESS_MITIGATION_IMAGE_LOAD_POLICY structure that specifies the policy flags for
	/// image loading.
	/// </term>
	/// </item>
	/// </list>
	/// </para>
	/// </param>
	/// <param name="value">The value.</param>
	/// <returns>
	/// If the function succeeds, it returns <c>TRUE</c>. If the function fails, it returns <c>FALSE</c>. To retrieve error values defined
	/// for this function, call <c>GetLastError</c>.
	/// </returns>
	/// <exception cref="ArgumentException"></exception>
	public static bool GetProcessMitigationPolicy<T>([In, AddAsMember] HPROCESS hProcess, PROCESS_MITIGATION_POLICY MitigationPolicy, [NotNullWhen(true)] out T? value)
	{
		bool isMask = MitigationPolicy == PROCESS_MITIGATION_POLICY.ProcessMitigationOptionsMask;
		if (!isMask && !CorrespondingTypeAttribute.CanGet(MitigationPolicy, typeof(T))) throw new ArgumentException($"{MitigationPolicy} cannot be used to get values of type {typeof(T)}.");
		int sz = isMask ? 16 : Marshal.SizeOf<T>();
		using SafeCoTaskMemHandle ptr = new(sz);
		if (!isMask)
		{
			if (GetProcessMitigationPolicy(hProcess, MitigationPolicy, (IntPtr)ptr, (uint)ptr.Size))
			{
				value = ptr.ToStructure<T>()!;
				return true;
			}
		}
		else
		{
			if (GetProcessMitigationPolicy(hProcess, MitigationPolicy, (IntPtr)ptr, (uint)ptr.Size))
			{
				value = (T)(object)ptr.ToArray<ulong>(2);
				return true;
			}
			else if (GetProcessMitigationPolicy(hProcess, MitigationPolicy, (IntPtr)ptr, 8))
			{
				value = (T)(object)ptr.ToArray<ulong>(1);
				return true;
			}
		}
		value = default;
		return false;
	}

	/// <summary>Retrieves the priority boost control state of the specified process.</summary>
	/// <param name="hProcess">
	/// <para>
	/// A handle to the process. This handle must have the <c>PROCESS_QUERY_INFORMATION</c> or <c>PROCESS_QUERY_LIMITED_INFORMATION</c>
	/// access right. For more information, see Process Security and Access Rights.
	/// </para>
	/// <para><c>Windows Server 2003 and Windows XP:</c> The handle must have the <c>PROCESS_QUERY_INFORMATION</c> access right.</para>
	/// </param>
	/// <param name="pDisablePriorityBoost">
	/// A pointer to a variable that receives the priority boost control state. A value of TRUE indicates that dynamic boosting is disabled.
	/// A value of FALSE indicates normal behavior.
	/// </param>
	/// <returns>
	/// <para>
	/// If the function succeeds, the return value is nonzero. In that case, the variable pointed to by the pDisablePriorityBoost parameter
	/// receives the priority boost control state.
	/// </para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// BOOL WINAPI GetProcessPriorityBoost( _In_ HANDLE hProcess, _Out_ PBOOL pDisablePriorityBoost); https://msdn.microsoft.com/en-us/library/windows/desktop/ms683220(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms683220")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool GetProcessPriorityBoost([In, AddAsMember] HPROCESS hProcess, [MarshalAs(UnmanagedType.Bool)] out bool pDisablePriorityBoost);

	/// <summary>Retrieves the shutdown parameters for the currently calling process.</summary>
	/// <param name="lpdwLevel">
	/// <para>
	/// A pointer to a variable that receives the shutdown priority level. Higher levels shut down first. System level shutdown orders are
	/// reserved for system components. Higher numbers shut down first. Following are the level conventions.
	/// </para>
	/// <para>
	/// <list type="table">
	/// <listheader>
	/// <term>Value</term>
	/// <term>Meaning</term>
	/// </listheader>
	/// <item>
	/// <term>000-0FF</term>
	/// <term>System reserved last shutdown range.</term>
	/// </item>
	/// <item>
	/// <term>100-1FF</term>
	/// <term>Application reserved last shutdown range.</term>
	/// </item>
	/// <item>
	/// <term>200-2FF</term>
	/// <term>Application reserved &amp;quot;in between&amp;quot; shutdown range.</term>
	/// </item>
	/// <item>
	/// <term>300-3FF</term>
	/// <term>Application reserved first shutdown range.</term>
	/// </item>
	/// <item>
	/// <term>400-4FF</term>
	/// <term>System reserved first shutdown range.</term>
	/// </item>
	/// </list>
	/// </para>
	/// <para>All processes start at shutdown level 0x280.</para>
	/// </param>
	/// <param name="lpdwFlags">
	/// <para>A pointer to a variable that receives the shutdown flags. This parameter can be the following value.</para>
	/// <para>
	/// <list type="table">
	/// <listheader>
	/// <term>Value</term>
	/// <term>Meaning</term>
	/// </listheader>
	/// <item>
	/// <term>SHUTDOWN_NORETRY0x00000001</term>
	/// <term>
	/// If this process takes longer than the specified timeout to shut down, do not display a retry dialog box for the user. Instead, just
	/// cause the process to directly exit.
	/// </term>
	/// </item>
	/// </list>
	/// </para>
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// BOOL WINAPI GetProcessShutdownParameters( _Out_ LPDWORD lpdwLevel, _Out_ LPDWORD lpdwFlags); https://msdn.microsoft.com/en-us/library/windows/desktop/ms683221(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms683221")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool GetProcessShutdownParameters(out uint lpdwLevel, out SHUTDOWN lpdwFlags);

	/// <summary>Retrieves timing information for the specified process.</summary>
	/// <param name="hProcess">
	/// <para>
	/// A handle to the process whose timing information is sought. The handle must have the <c>PROCESS_QUERY_INFORMATION</c> or
	/// <c>PROCESS_QUERY_LIMITED_INFORMATION</c> access right. For more information, see Process Security and Access Rights.
	/// </para>
	/// <para><c>Windows Server 2003 and Windows XP:</c> The handle must have the <c>PROCESS_QUERY_INFORMATION</c> access right.</para>
	/// </param>
	/// <param name="lpCreationTime">A pointer to a <c>FILETIME</c> structure that receives the creation time of the process.</param>
	/// <param name="lpExitTime">
	/// A pointer to a <c>FILETIME</c> structure that receives the exit time of the process. If the process has not exited, the content of
	/// this structure is undefined.
	/// </param>
	/// <param name="lpKernelTime">
	/// A pointer to a <c>FILETIME</c> structure that receives the amount of time that the process has executed in kernel mode. The time that
	/// each of the threads of the process has executed in kernel mode is determined, and then all of those times are summed together to
	/// obtain this value.
	/// </param>
	/// <param name="lpUserTime">
	/// A pointer to a <c>FILETIME</c> structure that receives the amount of time that the process has executed in user mode. The time that
	/// each of the threads of the process has executed in user mode is determined, and then all of those times are summed together to obtain
	/// this value. Note that this value can exceed the amount of real time elapsed (between lpCreationTime and lpExitTime) if the process
	/// executes across multiple CPU cores.
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// BOOL WINAPI GetProcessTimes( _In_ HANDLE hProcess, _Out_ LPFILETIME lpCreationTime, _Out_ LPFILETIME lpExitTime, _Out_ LPFILETIME
	// lpKernelTime, _Out_ LPFILETIME lpUserTime); https://msdn.microsoft.com/en-us/library/windows/desktop/ms683223(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms683223")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool GetProcessTimes([In, AddAsMember] HPROCESS hProcess, out FILETIME lpCreationTime, out FILETIME lpExitTime, out FILETIME lpKernelTime,
		out FILETIME lpUserTime);

	/// <summary>Retrieves the major and minor version numbers of the system on which the specified process expects to run.</summary>
	/// <param name="ProcessId">The process identifier of the process of interest. A value of zero specifies the calling process.</param>
	/// <returns>
	/// <para>
	/// If the function succeeds, the return value is the version of the system on which the process expects to run. The high word of the
	/// return value contains the major version number. The low word of the return value contains the minor version number.
	/// </para>
	/// <para>
	/// If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>. The function fails if
	/// ProcessId is an invalid value.
	/// </para>
	/// </returns>
	// DWORD WINAPI GetProcessVersion( _In_ DWORD ProcessId); https://msdn.microsoft.com/en-us/library/windows/desktop/ms683224(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms683224")]
	public static extern uint GetProcessVersion(uint ProcessId = 0);

	/// <summary>Retrieves the contents of the <c>STARTUPINFO</c> structure that was specified when the calling process was created.</summary>
	/// <param name="lpStartupInfo">A pointer to a <c>STARTUPINFO</c> structure that receives the startup information.</param>
	/// <returns>
	/// <para>This function does not return a value.</para>
	/// <para>
	/// If an error occurs, the ANSI version of this function ( <c>GetStartupInfoA</c>) can raise an exception. The Unicode version (
	/// <c>GetStartupInfoW</c>) does not fail.
	/// </para>
	/// </returns>
	// VOID WINAPI GetStartupInfo( _Out_ LPSTARTUPINFO lpStartupInfo); https://msdn.microsoft.com/en-us/library/windows/desktop/ms683230(v=vs.85).aspx
	[PInvokeData("WinBase.h", MSDNShortId = "ms683230")]
	public static void GetStartupInfo(out STARTUPINFO lpStartupInfo)
	{ GetStartupInfo(out STARTUPINFO_OUT sio); lpStartupInfo = sio; }

	/// <summary>Allows an application to query the available CPU Sets on the system, and their current state.</summary>
	/// <param name="Information">
	/// A pointer to a <c>SYSTEM_CPU_SET_INFORMATION</c> structure that receives the CPU Set data. Pass NULL with a buffer length of 0 to
	/// determine the required buffer size.
	/// </param>
	/// <param name="BufferLength">The length, in bytes, of the output buffer passed as the Information argument.</param>
	/// <param name="ReturnedLength">
	/// The length, in bytes, of the valid data in the output buffer if the buffer is large enough, or the required size of the output
	/// buffer. If no CPU Sets exist, this value will be 0.
	/// </param>
	/// <param name="Process">
	/// An optional handle to a process. This process is used to determine the value of the <c>AllocatedToTargetProcess</c> flag in the
	/// SYSTEM_CPU_SET_INFORMATION structure. If a CPU Set is allocated to the specified process, the flag is set. Otherwise, it is clear.
	/// This handle must have the PROCESS_QUERY_LIMITED_INFORMATION access right. The value returned by <c>GetCurrentProcess</c> may also be
	/// specified here.
	/// </param>
	/// <param name="Flags">Reserved, must be 0.</param>
	/// <returns>
	/// If the API succeeds it returns TRUE. If it fails, the error reason is available through <c>GetLastError</c>. If the Information
	/// buffer was NULL or not large enough, the error code ERROR_INSUFFICIENT_BUFFER is returned. This API cannot fail when passed valid
	/// parameters and a buffer that is large enough to hold all of the return data.
	/// </returns>
	// BOOL WINAPI GetSystemCpuSetInformation( _Out_opt_ PSYSTEM_CPU_SET_INFORMATION Information, _In_ ULONG BufferLength, _Out_ PULONG
	// ReturnedLength, _In_opt_ HANDLE Process, _Reserved_ ULONG Flags); https://msdn.microsoft.com/en-us/library/windows/desktop/mt186425(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("Processthreadapi.h", MSDNShortId = "mt186425")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool GetSystemCpuSetInformation(IntPtr Information, uint BufferLength, out uint ReturnedLength, [Optional] HPROCESS Process, [Optional] uint Flags);

	/// <summary>Allows an application to query the available CPU Sets on the system, and their current state.</summary>
	/// <param name="Process">
	/// An optional handle to a process. This process is used to determine the value of the <c>AllocatedToTargetProcess</c> flag in the
	/// SYSTEM_CPU_SET_INFORMATION structure. If a CPU Set is allocated to the specified process, the flag is set. Otherwise, it is clear.
	/// This handle must have the PROCESS_QUERY_LIMITED_INFORMATION access right. The value returned by <c>GetCurrentProcess</c> may also be
	/// specified here.
	/// </param>
	/// <returns>A list of <c>SYSTEM_CPU_SET_INFORMATION</c> structures with CPU Set data.</returns>
	public static IEnumerable<SYSTEM_CPU_SET_INFORMATION> GetSystemCpuSetInformation([Optional] HPROCESS Process)
	{
		if (!GetSystemCpuSetInformation(IntPtr.Zero, 0, out uint sz, Process) || sz == 0)
		{
			Win32Error.ThrowLastErrorUnless(Win32Error.ERROR_INSUFFICIENT_BUFFER);
		}
		using SafeCoTaskMemHandle ptr = new((int)sz);
		if (!GetSystemCpuSetInformation((IntPtr)ptr, sz, out sz, Process))
			Win32Error.ThrowLastError();
		int offset = 0;
		while (offset < sz)
		{
			IntPtr sptr = ptr.DangerousGetHandle().Offset(offset);
			int structSize = Marshal.ReadInt32(sptr);
			yield return sptr.ToStructure<SYSTEM_CPU_SET_INFORMATION>(sz - offset);
			offset += structSize;
		}
	}

	/// <summary>
	/// Retrieves system timing information. On a multiprocessor system, the values returned are the sum of the designated times across all processors.
	/// </summary>
	/// <param name="lpIdleTime">A pointer to a <c>FILETIME</c> structure that receives the amount of time that the system has been idle.</param>
	/// <param name="lpKernelTime">
	/// A pointer to a <c>FILETIME</c> structure that receives the amount of time that the system has spent executing in Kernel mode
	/// (including all threads in all processes, on all processors). This time value also includes the amount of time the system has been idle.
	/// </param>
	/// <param name="lpUserTime">
	/// A pointer to a <c>FILETIME</c> structure that receives the amount of time that the system has spent executing in User mode (including
	/// all threads in all processes, on all processors).
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// BOOL WINAPI GetSystemTimes( _Out_opt_ LPFILETIME lpIdleTime, _Out_opt_ LPFILETIME lpKernelTime, _Out_opt_ LPFILETIME lpUserTime); https://msdn.microsoft.com/en-us/library/windows/desktop/ms724400(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("Winbase.h", MSDNShortId = "ms724400")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool GetSystemTimes(out FILETIME lpIdleTime, out FILETIME lpKernelTime, out FILETIME lpUserTime);

	/// <summary>
	/// <para>Retrieves the context of the specified thread.</para>
	/// <para>A 64-bit application can retrieve the context of a WOW64 thread using the <c>Wow64GetThreadContext</c> function.</para>
	/// </summary>
	/// <param name="hThread">
	/// <para>
	/// A handle to the thread whose context is to be retrieved. The handle must have <c>THREAD_GET_CONTEXT</c> access to the thread. For
	/// more information, see Thread Security and Access Rights.
	/// </para>
	/// <para><c>WOW64:</c> The handle must also have <c>THREAD_QUERY_INFORMATION</c> access.</para>
	/// </param>
	/// <param name="lpContext">
	/// A pointer to a <c>CONTEXT</c> structure that receives the appropriate context of the specified thread. The value of the
	/// <c>ContextFlags</c> member of this structure specifies which portions of a thread's context are retrieved. The <c>CONTEXT</c>
	/// structure is highly processor specific. Refer to the WinNT.h header file for processor-specific definitions of this structures and
	/// any alignment requirements.
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// BOOL WINAPI GetThreadContext( _In_ HANDLE hThread, _Inout_ LPCONTEXT lpContext); https://msdn.microsoft.com/en-us/library/windows/desktop/ms679362(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms679362")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool GetThreadContext([In, AddAsMember] HTHREAD hThread, ref CONTEXT lpContext);

	/// <summary>Retrieves the description that was assigned to a thread by calling SetThreadDescription.</summary>
	/// <param name="hThread">
	/// A handle to the thread for which to retrieve the description. The handle must have THREAD_QUERY_LIMITED_INFORMATION access.
	/// </param>
	/// <param name="ppszThreadDescription">A Unicode string that contains the description of the thread.</param>
	/// <returns>
	/// If the function succeeds, the return value is the <c>HRESULT</c> that denotes a successful operation. If the function fails, the
	/// return value is an <c>HRESULT</c> that denotes the error.
	/// </returns>
	/// <remarks>
	/// <para>
	/// The description for a thread can change at any time. For example, a different thread can change the description of a thread of
	/// interest while you try to retrieve that description.
	/// </para>
	/// <para>Thread descriptions do not need to be unique.</para>
	/// </remarks>
	// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreaddescription HRESULT
	// GetThreadDescription( HANDLE hThread, PWSTR *ppszThreadDescription );
	[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
	[PInvokeData("processthreadsapi.h", MSDNShortId = "9CFF0A2D-2196-4AE0-8F77-229A8AB7A3E8")]
	public static extern HRESULT GetThreadDescription(HTHREAD hThread, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(LocalStringMarshaler))] out string ppszThreadDescription);

	/// <summary>Retrieves the thread identifier of the specified thread.</summary>
	/// <param name="Thread">
	/// <para>
	/// A handle to the thread. The handle must have the THREAD_QUERY_INFORMATION or THREAD_QUERY_LIMITED_INFORMATION access right. For more
	/// information about access rights, see Thread Security and Access Rights.
	/// </para>
	/// <para><c>Windows Server 2003:</c> The handle must have the THREAD_QUERY_INFORMATION access right.</para>
	/// </param>
	/// <returns>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</returns>
	// DWORD WINAPI GetThreadId( _In_ HANDLE Thread); https://msdn.microsoft.com/en-us/library/windows/desktop/ms683233(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms683233")]
	public static extern uint GetThreadId([In, AddAsMember] HTHREAD Thread);

	/// <summary>Retrieves the processor number of the ideal processor for the specified thread.</summary>
	/// <param name="hThread">
	/// A handle to the thread for which to retrieve the ideal processor. This handle must have been created with the
	/// THREAD_QUERY_LIMITED_INFORMATION access right. For more information, see Thread Security and Access Rights.
	/// </param>
	/// <param name="lpIdealProcessor">Points to <c>PROCESSOR_NUMBER</c> structure to receive the number of the ideal processor.</param>
	/// <returns>
	/// <para>If the function succeeds, it returns a nonzero value.</para>
	/// <para>If the function fails, it returns zero. To get extended error information, use <c>GetLastError</c>.</para>
	/// </returns>
	// BOOL GetThreadIdealProcessorEx( _In_ HANDLE hThread, _Out_ PPROCESSOR_NUMBER lpIdealProcessor); https://msdn.microsoft.com/en-us/library/windows/desktop/dd405499(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "dd405499")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool GetThreadIdealProcessorEx([In, AddAsMember] HTHREAD hThread, out PROCESSOR_NUMBER lpIdealProcessor);

	/// <summary>Retrieves information about the specified thread.</summary>
	/// <param name="hThread">
	/// A handle to the thread. The handle must have THREAD_QUERY_INFORMATION access rights. For more information, see Thread Security and
	/// Access Rights.
	/// </param>
	/// <param name="ThreadInformationClass">
	/// The class of information to retrieve. The only supported values are <c>ThreadMemoryPriority</c> and <c>ThreadPowerThrottling</c>.
	/// </param>
	/// <param name="ThreadInformation">
	/// <para>Pointer to a structure to receive the type of information specified by the ThreadInformationClass parameter.</para>
	/// <para>
	/// If the ThreadInformationClass parameter is <c>ThreadMemoryPriority</c>, this parameter must point to a
	/// <c>MEMORY_PRIORITY_INFORMATION</c> structure.
	/// </para>
	/// <para>
	/// If the ThreadInformationClass parameter is <c>ThreadPowerThrottling</c>, this parameter must point to a
	/// <c>THREAD_POWER_THROTTLING_STATE</c> structure.
	/// </para>
	/// </param>
	/// <param name="ThreadInformationSize">
	/// <para>The size in bytes of the structure specified by the ThreadInformation parameter.</para>
	/// <para>If the ThreadInformationClass parameter is <c>ThreadMemoryPriority</c>, this parameter must be .</para>
	/// <para>If the ThreadInformationClass parameter is <c>ThreadPowerThrottling</c>, this parameter must be .</para>
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// BOOL GetThreadInformation( _In_ HANDLE hThread, _In_ THREAD_INFORMATION_CLASS ThreadInformationClass, _Out_writes_bytes_
	// ThreadInformation, _In_ DWORD ThreadInformationSize);// https://msdn.microsoft.com/en-us/library/windows/desktop/hh448382(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "hh448382")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool GetThreadInformation(HTHREAD hThread, THREAD_INFORMATION_CLASS ThreadInformationClass, IntPtr ThreadInformation, uint ThreadInformationSize);

	/// <summary>Retrieves information about the specified thread.</summary>
	/// <param name="hThread">
	/// A handle to the thread. The handle must have THREAD_QUERY_INFORMATION access rights. For more information, see Thread Security and
	/// Access Rights.
	/// </param>
	/// <param name="ThreadInformationClass">
	/// The class of information to retrieve. The only supported values are <c>ThreadMemoryPriority</c> and <c>ThreadPowerThrottling</c>.
	/// </param>
	/// <returns>
	/// <para>A structure that receives the type of information specified by the ThreadInformationClass parameter.</para>
	/// <para>
	/// If the ThreadInformationClass parameter is <c>ThreadMemoryPriority</c>, this parameter must point to a
	/// <c>MEMORY_PRIORITY_INFORMATION</c> structure.
	/// </para>
	/// <para>
	/// If the ThreadInformationClass parameter is <c>ThreadPowerThrottling</c>, this parameter must point to a
	/// <c>THREAD_POWER_THROTTLING_STATE</c> structure.
	/// </para>
	/// </returns>
	[PInvokeData("WinBase.h", MSDNShortId = "hh448382")]
	public static T GetThreadInformation<T>([In, AddAsMember] HTHREAD hThread, THREAD_INFORMATION_CLASS ThreadInformationClass) where T : struct
	{
		if (!CorrespondingTypeAttribute.CanGet(ThreadInformationClass, typeof(T))) throw new ArgumentException($"{ThreadInformationClass} cannot be used to get values of type {typeof(T)}.");
		using SafeHGlobalHandle mem = SafeHGlobalHandle.CreateFromStructure(ReflectionExtensions.CreateOrDefault<T>());
		if (!GetThreadInformation(hThread, ThreadInformationClass, (IntPtr)mem, (uint)mem.Size))
			Win32Error.ThrowLastError();
		return mem.ToStructure<T>();
	}

	/// <summary>Determines whether a specified thread has any I/O requests pending.</summary>
	/// <param name="hThread">
	/// A handle to the thread in question. This handle must have been created with the THREAD_QUERY_INFORMATION access right. For more
	/// information, see Thread Security and Access Rights.
	/// </param>
	/// <param name="lpIOIsPending">
	/// A pointer to a variable which the function sets to TRUE if the specified thread has one or more I/O requests pending, or to FALSE otherwise.
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// BOOL WINAPI GetThreadIOPendingFlag( _In_ HANDLE hThread, _Inout_ PBOOL lpIOIsPending); https://msdn.microsoft.com/en-us/library/windows/desktop/ms683234(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms683234")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool GetThreadIOPendingFlag([In, AddAsMember] HTHREAD hThread, [MarshalAs(UnmanagedType.Bool)] out bool lpIOIsPending);

	/// <summary>
	/// Retrieves the priority value for the specified thread. This value, together with the priority class of the thread's process,
	/// determines the thread's base-priority level.
	/// </summary>
	/// <param name="hThread">
	/// <para>A handle to the thread.</para>
	/// <para>
	/// The handle must have the <c>THREAD_QUERY_INFORMATION</c> or <c>THREAD_QUERY_LIMITED_INFORMATION</c> access right. For more
	/// information, see Thread Security and Access Rights.
	/// </para>
	/// <para><c>Windows Server 2003:</c> The handle must have the <c>THREAD_QUERY_INFORMATION</c> access right.</para>
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is the thread's priority level.</para>
	/// <para>If the function fails, the return value is <c>THREAD_PRIORITY_ERROR_RETURN</c>. To get extended error information, call <c>GetLastError</c>.</para>
	/// <para><c>Windows Phone 8.1:</c> This function will always return <c>THREAD_PRIORITY_NORMAL</c>.</para>
	/// <para>The thread's priority level is one of the following values.</para>
	/// <para>
	/// <list type="table">
	/// <listheader>
	/// <term>Return code/value</term>
	/// <term>Description</term>
	/// </listheader>
	/// <item>
	/// <term>THREAD_PRIORITY_ABOVE_NORMAL1</term>
	/// <term>Priority 1 point above the priority class.</term>
	/// </item>
	/// <item>
	/// <term>THREAD_PRIORITY_BELOW_NORMAL-1</term>
	/// <term>Priority 1 point below the priority class.</term>
	/// </item>
	/// <item>
	/// <term>THREAD_PRIORITY_HIGHEST2</term>
	/// <term>Priority 2 points above the priority class.</term>
	/// </item>
	/// <item>
	/// <term>THREAD_PRIORITY_IDLE-15</term>
	/// <term>
	/// Base priority of 1 for IDLE_PRIORITY_CLASS, BELOW_NORMAL_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, ABOVE_NORMAL_PRIORITY_CLASS, or
	/// HIGH_PRIORITY_CLASS processes, and a base priority of 16 for REALTIME_PRIORITY_CLASS processes.
	/// </term>
	/// </item>
	/// <item>
	/// <term>THREAD_PRIORITY_LOWEST-2</term>
	/// <term>Priority 2 points below the priority class.</term>
	/// </item>
	/// <item>
	/// <term>THREAD_PRIORITY_NORMAL0</term>
	/// <term>Normal priority for the priority class.</term>
	/// </item>
	/// <item>
	/// <term>THREAD_PRIORITY_TIME_CRITICAL15</term>
	/// <term>
	/// Base-priority level of 15 for IDLE_PRIORITY_CLASS, BELOW_NORMAL_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, ABOVE_NORMAL_PRIORITY_CLASS,
	/// or HIGH_PRIORITY_CLASS processes, and a base-priority level of 31 for REALTIME_PRIORITY_CLASS processes.
	/// </term>
	/// </item>
	/// </list>
	/// </para>
	/// <para>
	/// If the thread has the <c>REALTIME_PRIORITY_CLASS</c> base class, this function can also return one of the following values: -7,
	/// -6, -5, -4, -3, 3, 4, 5, or 6. For more information, see Scheduling Priorities.
	/// </para>
	/// </returns>
	// int WINAPI GetThreadPriority( _In_ HANDLE hThread);// https://msdn.microsoft.com/en-us/library/windows/desktop/ms683235(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms683235")]
	public static extern int GetThreadPriority([In, AddAsMember] HTHREAD hThread);

	/// <summary>Retrieves the priority boost control state of the specified thread.</summary>
	/// <param name="hThread">
	/// <para>
	/// A handle to the thread. The handle must have the <c>THREAD_QUERY_INFORMATION</c> or <c>THREAD_QUERY_LIMITED_INFORMATION</c> access
	/// right. For more information, see Thread Security and Access Rights.
	/// </para>
	/// <para><c>Windows Server 2003 and Windows XP:</c> The handle must have the <c>THREAD_QUERY_INFORMATION</c> access right.</para>
	/// </param>
	/// <param name="pDisablePriorityBoost">
	/// A pointer to a variable that receives the priority boost control state. A value of TRUE indicates that dynamic boosting is disabled.
	/// A value of FALSE indicates normal behavior.
	/// </param>
	/// <returns>
	/// <para>
	/// If the function succeeds, the return value is nonzero. In that case, the variable pointed to by the pDisablePriorityBoost parameter
	/// receives the priority boost control state.
	/// </para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// BOOL WINAPI GetThreadPriorityBoost( _In_ HANDLE hThread, _Out_ PBOOL pDisablePriorityBoost); https://msdn.microsoft.com/en-us/library/windows/desktop/ms683236(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms683236")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool GetThreadPriorityBoost([In, AddAsMember] HTHREAD hThread, [MarshalAs(UnmanagedType.Bool)] out bool pDisablePriorityBoost);

	/// <summary>
	/// Returns the explicit CPU Set assignment of the specified thread, if any assignment was set using the <c>SetThreadSelectedCpuSets</c>
	/// API. If no explicit assignment is set, <c>RequiredIdCount</c> is set to 0 and the function returns TRUE.
	/// </summary>
	/// <param name="Thread">
	/// Specifies the thread for which to query the selected CPU Sets. This handle must have the THREAD_QUERY_LIMITED_INFORMATION access
	/// right. The value returned by <c>GetCurrentThread</c> can also be specified here.
	/// </param>
	/// <param name="CpuSetIds">Specifies an optional buffer to retrieve the list of CPU Set identifiers.</param>
	/// <param name="CpuSetIdCount">
	/// Specifies the capacity of the buffer specified in <c>CpuSetIds</c>. If the buffer is NULL, this must be 0.
	/// </param>
	/// <param name="RequiredIdCount">
	/// Specifies the required capacity of the buffer to hold the entire list of thread selected CPU Sets. On successful return, this
	/// specifies the number of IDs filled into the buffer.
	/// </param>
	/// <returns>
	/// This API returns TRUE on success. If the buffer is not large enough, the <c>GetLastError</c> value is ERROR_INSUFFICIENT_BUFFER. This
	/// API cannot fail when passed valid parameters and the return buffer is large enough.
	/// </returns>
	// BOOL WINAPI GetThreadSelectedCpuSets( _In_ HANDLE Thread, _Out_opt_ PULONG CpuSetIds, _In_ ULONG CpuSetIdCount, _Out_ PULONG
	// RequiredIdCount); https://msdn.microsoft.com/en-us/library/windows/desktop/mt186426(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("Processthreadapi.h", MSDNShortId = "mt186426")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool GetThreadSelectedCpuSets(HTHREAD Thread, IntPtr CpuSetIds, uint CpuSetIdCount, out uint RequiredIdCount);

	/// <summary>
	/// Returns the explicit CPU Set assignment of the specified thread, if any assignment was set using the <c>SetThreadSelectedCpuSets</c>
	/// API. If no explicit assignment is set, <c>RequiredIdCount</c> is set to 0 and the function returns TRUE.
	/// </summary>
	/// <param name="Thread">
	/// Specifies the thread for which to query the selected CPU Sets. This handle must have the THREAD_QUERY_LIMITED_INFORMATION access
	/// right. The value returned by <c>GetCurrentThread</c> can also be specified here.
	/// </param>
	/// <returns>The list of CPU Set identifiers.</returns>
	[PInvokeData("Processthreadapi.h", MSDNShortId = "mt186426")]
	public static uint[] GetThreadSelectedCpuSets([In, AddAsMember] HTHREAD Thread)
	{
		uint cnt = (uint)Environment.ProcessorCount;
		if (cnt == 0) return [];
		SafeCoTaskMemHandle iptr = new((int)cnt * Marshal.SizeOf<uint>());
		if (!GetThreadSelectedCpuSets(Thread, (IntPtr)iptr, cnt, out cnt)) Win32Error.ThrowLastError();
		return iptr.ToArray<uint>((int)cnt);
	}

	/// <summary>Retrieves timing information for the specified thread.</summary>
	/// <param name="hThread">
	/// <para>
	/// A handle to the thread whose timing information is sought. The handle must have the <c>THREAD_QUERY_INFORMATION</c> or
	/// <c>THREAD_QUERY_LIMITED_INFORMATION</c> access right. For more information, see Thread Security and Access Rights.
	/// </para>
	/// <para><c>Windows Server 2003 and Windows XP:</c> The handle must have the <c>THREAD_QUERY_INFORMATION</c> access right.</para>
	/// </param>
	/// <param name="lpCreationTime">A pointer to a <c>FILETIME</c> structure that receives the creation time of the thread.</param>
	/// <param name="lpExitTime">
	/// A pointer to a <c>FILETIME</c> structure that receives the exit time of the thread. If the thread has not exited, the content of this
	/// structure is undefined.
	/// </param>
	/// <param name="lpKernelTime">
	/// A pointer to a <c>FILETIME</c> structure that receives the amount of time that the thread has executed in kernel mode.
	/// </param>
	/// <param name="lpUserTime">
	/// A pointer to a <c>FILETIME</c> structure that receives the amount of time that the thread has executed in user mode.
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// BOOL WINAPI GetThreadTimes( _In_ HANDLE hThread, _Out_ LPFILETIME lpCreationTime, _Out_ LPFILETIME lpExitTime, _Out_ LPFILETIME
	// lpKernelTime, _Out_ LPFILETIME lpUserTime);// https://msdn.microsoft.com/en-us/library/windows/desktop/ms683237(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms683237")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool GetThreadTimes([In, AddAsMember] HTHREAD hThread, out FILETIME lpCreationTime, out FILETIME lpExitTime, out FILETIME lpKernelTime,
		out FILETIME lpUserTime);

	/// <summary>Initializes the specified list of attributes for process and thread creation.</summary>
	/// <param name="lpAttributeList">
	/// The attribute list. This parameter can be NULL to determine the buffer size required to support the specified number of attributes.
	/// </param>
	/// <param name="dwAttributeCount">The count of attributes to be added to the list.</param>
	/// <param name="dwFlags">This parameter is reserved and must be zero.</param>
	/// <param name="lpSize">
	/// <para>
	/// If lpAttributeList is not NULL, this parameter specifies the size in bytes of the lpAttributeList buffer on input. On output, this
	/// parameter receives the size in bytes of the initialized attribute list.
	/// </para>
	/// <para>If lpAttributeList is NULL, this parameter receives the required buffer size in bytes.</para>
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// BOOL WINAPI InitializeProcThreadAttributeList( _Out_opt_ LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList, _In_ DWORD dwAttributeCount,
	// _Reserved_ DWORD dwFlags, _Inout_ PSIZE_T lpSize); https://msdn.microsoft.com/en-us/library/windows/desktop/ms683481(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms683481")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool InitializeProcThreadAttributeList(IntPtr lpAttributeList, uint dwAttributeCount, [Optional] uint dwFlags, ref SizeT lpSize);

	/// <summary>Determines whether the specified process is considered critical.</summary>
	/// <param name="hProcess">
	/// A handle to the process to query. The process must have been opened with <c>PROCESS_QUERY_LIMITED_INFORMATION</c> access.
	/// </param>
	/// <param name="Critical">A pointer to the <c>BOOL</c> value this function will use to indicate whether the process is considered critical.</param>
	/// <returns>
	/// This routine returns FALSE on failure. Any other value indicates success. Call <c>GetLastError</c> to query for the specific error
	/// reason on failure.
	/// </returns>
	// BOOL WINAPI IsProcessCritical( _In_ HANDLE hProcess, _Out_ PBOOL Critical); https://msdn.microsoft.com/en-us/library/windows/desktop/dn386160(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("Processthreadsapi.h", MSDNShortId = "dn386160")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool IsProcessCritical([In, AddAsMember] HPROCESS hProcess, [MarshalAs(UnmanagedType.Bool)] out bool Critical);

	/// <summary>Determines whether the specified processor feature is supported by the current computer.</summary>
	/// <param name="ProcessorFeature">
	/// <para>The processor feature to be tested. This parameter can be one of the following values.</para>
	/// <para>
	/// <list type="table">
	/// <listheader>
	/// <term>Value</term>
	/// <term>Meaning</term>
	/// </listheader>
	/// <item>
	/// <term>PF_ARM_64BIT_LOADSTORE_ATOMIC25</term>
	/// <term>The 64-bit load/store atomic instructions are available.</term>
	/// </item>
	/// <item>
	/// <term>PF_ARM_DIVIDE_INSTRUCTION_AVAILABLE24</term>
	/// <term>The divide instructions are available.</term>
	/// </item>
	/// <item>
	/// <term>PF_ARM_EXTERNAL_CACHE_AVAILABLE26</term>
	/// <term>The external cache is available.</term>
	/// </item>
	/// <item>
	/// <term>PF_ARM_FMAC_INSTRUCTIONS_AVAILABLE27</term>
	/// <term>The floating-point multiply-accumulate instruction is available.</term>
	/// </item>
	/// <item>
	/// <term>PF_ARM_VFP_32_REGISTERS_AVAILABLE18</term>
	/// <term>The VFP/Neon: 32 x 64bit register bank is present. This flag has the same meaning as PF_ARM_VFP_EXTENDED_REGISTERS.</term>
	/// </item>
	/// <item>
	/// <term>PF_3DNOW_INSTRUCTIONS_AVAILABLE7</term>
	/// <term>The 3D-Now instruction set is available.</term>
	/// </item>
	/// <item>
	/// <term>PF_CHANNELS_ENABLED16</term>
	/// <term>The processor channels are enabled.</term>
	/// </item>
	/// <item>
	/// <term>PF_COMPARE_EXCHANGE_DOUBLE2</term>
	/// <term>The atomic compare and exchange operation (cmpxchg) is available.</term>
	/// </item>
	/// <item>
	/// <term>PF_COMPARE_EXCHANGE12814</term>
	/// <term>
	/// The atomic compare and exchange 128-bit operation (cmpxchg16b) is available.Windows Server 2003 and Windows XP/2000: This feature is
	/// not supported.
	/// </term>
	/// </item>
	/// <item>
	/// <term>PF_COMPARE64_EXCHANGE12815</term>
	/// <term>
	/// The atomic compare 64 and exchange 128-bit operation (cmp8xchg16) is available.Windows Server 2003 and Windows XP/2000: This feature
	/// is not supported.
	/// </term>
	/// </item>
	/// <item>
	/// <term>PF_FASTFAIL_AVAILABLE23</term>
	/// <term>_fastfail() is available.</term>
	/// </item>
	/// <item>
	/// <term>PF_FLOATING_POINT_EMULATED1</term>
	/// <term>
	/// Floating-point operations are emulated using a software emulator.This function returns a nonzero value if floating-point operations
	/// are emulated; otherwise, it returns zero.
	/// </term>
	/// </item>
	/// <item>
	/// <term>PF_FLOATING_POINT_PRECISION_ERRATA0</term>
	/// <term>On a Pentium, a floating-point precision error can occur in rare circumstances.</term>
	/// </item>
	/// <item>
	/// <term>PF_MMX_INSTRUCTIONS_AVAILABLE3</term>
	/// <term>The MMX instruction set is available.</term>
	/// </item>
	/// <item>
	/// <term>PF_NX_ENABLED12</term>
	/// <term>
	/// Data execution prevention is enabled.Windows XP/2000: This feature is not supported until Windows XP with SP2 and Windows Server 2003
	/// with SP1.
	/// </term>
	/// </item>
	/// <item>
	/// <term>PF_PAE_ENABLED9</term>
	/// <term>
	/// The processor is PAE-enabled. For more information, see Physical Address Extension.All x64 processors always return a nonzero value
	/// for this feature.
	/// </term>
	/// </item>
	/// <item>
	/// <term>PF_RDTSC_INSTRUCTION_AVAILABLE8</term>
	/// <term>The RDTSC instruction is available.</term>
	/// </item>
	/// <item>
	/// <term>PF_RDWRFSGSBASE_AVAILABLE22</term>
	/// <term>RDFSBASE, RDGSBASE, WRFSBASE, and WRGSBASE instructions are available.</term>
	/// </item>
	/// <item>
	/// <term>PF_SECOND_LEVEL_ADDRESS_TRANSLATION20</term>
	/// <term>Second Level Address Translation is supported by the hardware.</term>
	/// </item>
	/// <item>
	/// <term>PF_SSE3_INSTRUCTIONS_AVAILABLE13</term>
	/// <term>The SSE3 instruction set is available.Windows Server 2003 and Windows XP/2000: This feature is not supported.</term>
	/// </item>
	/// <item>
	/// <term>PF_VIRT_FIRMWARE_ENABLED21</term>
	/// <term>Virtualization is enabled in the firmware.</term>
	/// </item>
	/// <item>
	/// <term>PF_XMMI_INSTRUCTIONS_AVAILABLE6</term>
	/// <term>The SSE instruction set is available.</term>
	/// </item>
	/// <item>
	/// <term>PF_XMMI64_INSTRUCTIONS_AVAILABLE10</term>
	/// <term>The SSE2 instruction set is available.Windows 2000: This feature is not supported.</term>
	/// </item>
	/// <item>
	/// <term>PF_XSAVE_ENABLED17</term>
	/// <term>
	/// The processor implements the XSAVE and XRSTOR instructions.Windows Server 2008, Windows Vista, Windows Server 2003 and Windows
	/// XP/2000: This feature is not supported until Windows 7 and Windows Server 2008 R2.
	/// </term>
	/// </item>
	/// </list>
	/// </para>
	/// </param>
	/// <returns>
	/// <para>If the feature is supported, the return value is a nonzero value.</para>
	/// <para>If the feature is not supported, the return value is zero.</para>
	/// <para>
	/// If the HAL does not support detection of the feature, whether or not the hardware supports the feature, the return value is also zero.
	/// </para>
	/// </returns>
	// BOOL WINAPI IsProcessorFeaturePresent( _In_ DWORD ProcessorFeature); https://msdn.microsoft.com/en-us/library/windows/desktop/ms724482(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
	[PInvokeData("Winbase.h", MSDNShortId = "ms724482")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool IsProcessorFeaturePresent(PROCESSOR_FEATURE ProcessorFeature);

	/// <summary>Opens an existing local process object.</summary>
	/// <param name="dwDesiredAccess">
	/// <para>
	/// The access to the process object. This access right is checked against the security descriptor for the process. This parameter can be
	/// one or more of the process access rights.
	/// </para>
	/// <para>
	/// If the caller has enabled the SeDebugPrivilege privilege, the requested access is granted regardless of the contents of the security descriptor.
	/// </para>
	/// </param>
	/// <param name="bInheritHandle">
	/// If this value is TRUE, processes created by this process will inherit the handle. Otherwise, the processes do not inherit this handle.
	/// </param>
	/// <param name="dwProcessId">
	/// <para>The identifier of the local process to be opened.</para>
	/// <para>
	/// If the specified process is the System Process (0x00000000), the function fails and the last error code is ERROR_INVALID_PARAMETER.
	/// If the specified process is the Idle process or one of the CSRSS processes, this function fails and the last error code is
	/// ERROR_ACCESS_DENIED because their access restrictions prevent user-level code from opening them.
	/// </para>
	/// <para>
	/// If you are using <c>GetCurrentProcessId</c> as an argument to this function, consider using <c>GetCurrentProcess</c> instead of
	/// OpenProcess, for improved performance.
	/// </para>
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is an open handle to the specified process.</para>
	/// <para>If the function fails, the return value is NULL. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// HANDLE WINAPI OpenProcess( _In_ DWORD dwDesiredAccess, _In_ BOOL bInheritHandle, _In_ DWORD dwProcessId); https://msdn.microsoft.com/en-us/library/windows/desktop/ms684320(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms684320")]
	public static extern SafeHPROCESS OpenProcess(ACCESS_MASK dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwProcessId);

	/// <summary>Opens an existing thread object.</summary>
	/// <param name="dwDesiredAccess">
	/// <para>
	/// The access to the thread object. This access right is checked against the security descriptor for the thread. This parameter can be
	/// one or more of the thread access rights.
	/// </para>
	/// <para>
	/// If the caller has enabled the SeDebugPrivilege privilege, the requested access is granted regardless of the contents of the security descriptor.
	/// </para>
	/// </param>
	/// <param name="bInheritHandle">
	/// If this value is TRUE, processes created by this process will inherit the handle. Otherwise, the processes do not inherit this handle.
	/// </param>
	/// <param name="dwThreadId">The identifier of the thread to be opened.</param>
	/// <returns>
	/// <para>If the function succeeds, the return value is an open handle to the specified thread.</para>
	/// <para>If the function fails, the return value is NULL. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// HANDLE WINAPI OpenThread( _In_ DWORD dwDesiredAccess, _In_ BOOL bInheritHandle, _In_ DWORD dwThreadId); https://msdn.microsoft.com/en-us/library/windows/desktop/ms684335(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms684335")]
	public static extern SafeHTHREAD OpenThread(ACCESS_MASK dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwThreadId);

	/// <summary>Retrieves the Remote Desktop Services session associated with a specified process.</summary>
	/// <param name="dwProcessId">
	/// Specifies a process identifier. Use the <c>GetCurrentProcessId</c> function to retrieve the process identifier for the current process.
	/// </param>
	/// <param name="pSessionId">
	/// Pointer to a variable that receives the identifier of the Remote Desktop Services session under which the specified process is
	/// running. To retrieve the identifier of the session currently attached to the console, use the <c>WTSGetActiveConsoleSessionId</c> function.
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is a nonzero value.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// BOOL ProcessIdToSessionId( _In_ DWORD dwProcessId, _Out_ DWORD *pSessionId ); https://msdn.microsoft.com/en-us/library/aa382990(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("Winbase.h", MSDNShortId = "aa382990")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool ProcessIdToSessionId(uint dwProcessId, out uint pSessionId);

	/// <summary>Retrieves the affinity update mode of the specified process.</summary>
	/// <param name="ProcessHandle">
	/// A handle to the process. The handle must have the PROCESS_QUERY_INFORMATION or PROCESS_QUERY_LIMITED_INFORMATION access right. For
	/// more information, see Process Security and Access Rights.
	/// </param>
	/// <param name="lpdwFlags">
	/// <para>The affinity update mode. This parameter can be one of the following values.</para>
	/// <para>
	/// <list type="table">
	/// <listheader>
	/// <term>Value</term>
	/// <term>Meaning</term>
	/// </listheader>
	/// <item>
	/// <term>0</term>
	/// <term>Dynamic update of the process affinity by the system is disabled.</term>
	/// </item>
	/// <item>
	/// <term>PROCESS_AFFINITY_ENABLE_AUTO_UPDATE0x00000001UL</term>
	/// <term>Dynamic update of the process affinity by the system is enabled.</term>
	/// </item>
	/// </list>
	/// </para>
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// BOOL WINAPI QueryProcessAffinityUpdateMode( _In_ HANDLE ProcessHandle, _Out_opt_ DWORD lpdwFlags); https://msdn.microsoft.com/en-us/library/windows/desktop/bb309062(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "bb309062")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool QueryProcessAffinityUpdateMode([In, AddAsMember] HPROCESS ProcessHandle, out PROCESS_AFFINITY_MODE lpdwFlags);

	/// <summary>Queries the value associated with a protected policy.</summary>
	/// <param name="PolicyGuid">The globally-unique identifier of the policy to query.</param>
	/// <param name="PolicyValue">Receives the value that the supplied policy is set to.</param>
	/// <returns>True if the function succeeds; otherwise, false.</returns>
	// BOOL WINAPI QueryProtectedPolicy( _In_ LPCGUID PolicyGuid, _Out_ PULONG_PTR PolicyValue); https://msdn.microsoft.com/en-us/library/windows/desktop/dn893591(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
	[PInvokeData("Winbase.h", MSDNShortId = "dn893591")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool QueryProtectedPolicy(in Guid PolicyGuid, out IntPtr PolicyValue);

	/// <summary>Adds a user-mode asynchronous procedure call (APC) object to the APC queue of the specified thread.</summary>
	/// <param name="pfnAPC">
	/// A pointer to the application-supplied APC function to be called when the specified thread performs an alertable wait operation. For
	/// more information, see APCProc.
	/// </param>
	/// <param name="hThread">
	/// A handle to the thread. The handle must have the <c>THREAD_SET_CONTEXT</c> access right. For more information, see Synchronization
	/// Object Security and Access Rights.
	/// </param>
	/// <param name="dwData">A single value that is passed to the APC function pointed to by the pfnAPC parameter.</param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>
	/// If the function fails, the return value is zero. To get extended error information, call GetLastError. <c>Windows Server 2003 and
	/// Windows XP:</c> There are no error values defined for this function that can be retrieved by calling GetLastError.
	/// </para>
	/// </returns>
	/// <remarks>
	/// <para>
	/// The APC support provided in the operating system allows an application to queue an APC object to a thread. To ensure successful
	/// execution of functions used by the APC, APCs should be queued only to threads in the caller's process.
	/// </para>
	/// <para>
	/// <c>Note</c> Queuing APCs to threads outside the caller's process is not recommended for a number of reasons. DLL rebasing can cause
	/// the addresses of functions used by the APC to be incorrect when the functions are executed outside the caller's process. Similarly,
	/// if a 64-bit process queues an APC to a 32-bit process or vice versa, addresses will be incorrect and the application will crash.
	/// Other factors can prevent successful function execution, even if the address is known.
	/// </para>
	/// <para>
	/// Each thread has its own APC queue. The queuing of an APC is a request for the thread to call the APC function. The operating system
	/// issues a software interrupt to direct the thread to call the APC function.
	/// </para>
	/// <para>
	/// When a user-mode APC is queued, the thread is not directed to call the APC function unless it is in an alertable state. After the
	/// thread is in an alertable state, the thread handles all pending APCs in first in, first out (FIFO) order, and the wait operation
	/// returns <c>WAIT_IO_COMPLETION</c>. A thread enters an alertable state by using SleepEx, SignalObjectAndWait, WaitForSingleObjectEx,
	/// WaitForMultipleObjectsEx, or MsgWaitForMultipleObjectsEx to perform an alertable wait operation.
	/// </para>
	/// <para>
	/// If an application queues an APC before the thread begins running, the thread begins by calling the APC function. After the thread
	/// calls an APC function, it calls the APC functions for all APCs in its APC queue.
	/// </para>
	/// <para>
	/// It is possible to sleep or wait for an object within the APC. If you perform an alertable wait inside an APC, it will recursively
	/// dispatch the APCs. This can cause a stack overflow.
	/// </para>
	/// <para>
	/// When the thread is terminated using the ExitThread or TerminateThread function, the APCs in its APC queue are lost. The APC functions
	/// are not called.
	/// </para>
	/// <para>
	/// When the thread is in the process of being terminated, calling QueueUserAPC to add to the thread's APC queue will fail with <c>(31) ERROR_GEN_FAILURE</c>.
	/// </para>
	/// <para>
	/// Note that the ReadFileEx, SetWaitableTimer, and WriteFileEx functions are implemented using an APC as the completion notification
	/// callback mechanism.
	/// </para>
	/// <para>
	/// To compile an application that uses this function, define <c>_WIN32_WINNT</c> as 0x0400 or later. For more information, see Using the
	/// Windows Headers.
	/// </para>
	/// </remarks>
	// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-queueuserapc DWORD QueueUserAPC( PAPCFUNC
	// pfnAPC, HANDLE hThread, ULONG_PTR dwData );
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("processthreadsapi.h", MSDNShortId = "5b141372-7c95-4eb2-987b-64fdf7d0783d")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool QueueUserAPC(PAPCFUNC pfnAPC, [In] HTHREAD hThread, IntPtr dwData);

	/// <summary>Decrements a thread's suspend count. When the suspend count is decremented to zero, the execution of the thread is resumed.</summary>
	/// <param name="hThread">
	/// <para>A handle to the thread to be restarted.</para>
	/// <para>This handle must have the THREAD_SUSPEND_RESUME access right. For more information, see Thread Security and Access Rights.</para>
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is the thread's previous suspend count.</para>
	/// <para>If the function fails, the return value is (DWORD) -1. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// DWORD WINAPI ResumeThread( _In_ HANDLE hThread); https://msdn.microsoft.com/en-us/library/windows/desktop/ms685086(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms685086")]
	public static extern uint ResumeThread([In, AddAsMember] HTHREAD hThread);

	/// <summary>
	/// Sets the priority class for the specified process. This value together with the priority value of each thread of the process
	/// determines each thread's base priority level.
	/// </summary>
	/// <param name="hProcess">
	/// <para>A handle to the process.</para>
	/// <para>
	/// The handle must have the <c>PROCESS_SET_INFORMATION</c> access right. For more information, see Process Security and Access Rights.
	/// </para>
	/// </param>
	/// <param name="dwPriorityClass">
	/// <para>The priority class for the process. This parameter can be one of the following values.</para>
	/// <para>
	/// <list type="table">
	/// <listheader>
	/// <term>Priority</term>
	/// <term>Meaning</term>
	/// </listheader>
	/// <item>
	/// <term>ABOVE_NORMAL_PRIORITY_CLASS0x00008000</term>
	/// <term>Process that has priority above NORMAL_PRIORITY_CLASS but below HIGH_PRIORITY_CLASS.</term>
	/// </item>
	/// <item>
	/// <term>BELOW_NORMAL_PRIORITY_CLASS0x00004000</term>
	/// <term>Process that has priority above IDLE_PRIORITY_CLASS but below NORMAL_PRIORITY_CLASS.</term>
	/// </item>
	/// <item>
	/// <term>HIGH_PRIORITY_CLASS0x00000080</term>
	/// <term>
	/// Process that performs time-critical tasks that must be executed immediately. The threads of the process preempt the threads of normal
	/// or idle priority class processes. An example is the Task List, which must respond quickly when called by the user, regardless of the
	/// load on the operating system. Use extreme care when using the high-priority class, because a high-priority class application can use
	/// nearly all available CPU time.
	/// </term>
	/// </item>
	/// <item>
	/// <term>IDLE_PRIORITY_CLASS0x00000040</term>
	/// <term>
	/// Process whose threads run only when the system is idle. The threads of the process are preempted by the threads of any process
	/// running in a higher priority class. An example is a screen saver. The idle-priority class is inherited by child processes.
	/// </term>
	/// </item>
	/// <item>
	/// <term>NORMAL_PRIORITY_CLASS0x00000020</term>
	/// <term>Process with no special scheduling needs.</term>
	/// </item>
	/// <item>
	/// <term>PROCESS_MODE_BACKGROUND_BEGIN0x00100000</term>
	/// <term>
	/// Begin background processing mode. The system lowers the resource scheduling priorities of the process (and its threads) so that it
	/// can perform background work without significantly affecting activity in the foreground.This value can be specified only if hProcess
	/// is a handle to the current process. The function fails if the process is already in background processing mode.Windows Server 2003
	/// and Windows XP: This value is not supported.
	/// </term>
	/// </item>
	/// <item>
	/// <term>PROCESS_MODE_BACKGROUND_END0x00200000</term>
	/// <term>
	/// End background processing mode. The system restores the resource scheduling priorities of the process (and its threads) as they were
	/// before the process entered background processing mode.This value can be specified only if hProcess is a handle to the current
	/// process. The function fails if the process is not in background processing mode.Windows Server 2003 and Windows XP: This value is not supported.
	/// </term>
	/// </item>
	/// <item>
	/// <term>REALTIME_PRIORITY_CLASS0x00000100</term>
	/// <term>
	/// Process that has the highest possible priority. The threads of the process preempt the threads of all other processes, including
	/// operating system processes performing important tasks. For example, a real-time process that executes for more than a very brief
	/// interval can cause disk caches not to flush or cause the mouse to be unresponsive.
	/// </term>
	/// </item>
	/// </list>
	/// </para>
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// BOOL WINAPI SetPriorityClass( _In_ HANDLE hProcess, _In_ DWORD dwPriorityClass); https://msdn.microsoft.com/en-us/library/windows/desktop/ms686219(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms686219")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool SetPriorityClass([In, AddAsMember] HPROCESS hProcess, CREATE_PROCESS dwPriorityClass);

	/// <summary>Sets the affinity update mode of the specified process.</summary>
	/// <param name="ProcessHandle">A handle to the process. This handle must be returned by the <c>GetCurrentProcess</c> function.</param>
	/// <param name="dwFlags">
	/// <para>The affinity update mode. This parameter can be one of the following values.</para>
	/// <para>
	/// <list type="table">
	/// <listheader>
	/// <term>Value</term>
	/// <term>Meaning</term>
	/// </listheader>
	/// <item>
	/// <term>0</term>
	/// <term>Disables dynamic update of the process affinity by the system.</term>
	/// </item>
	/// <item>
	/// <term>PROCESS_AFFINITY_ENABLE_AUTO_UPDATE0x00000001UL</term>
	/// <term>Enables dynamic update of the process affinity by the system.</term>
	/// </item>
	/// </list>
	/// </para>
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// BOOL WINAPI SetProcessAffinityUpdateMode( _In_ HANDLE ProcessHandle, _In_ DWORD dwFlags); https://msdn.microsoft.com/en-us/library/windows/desktop/bb309063(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "bb309063")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool SetProcessAffinityUpdateMode([In, AddAsMember] HPROCESS ProcessHandle, PROCESS_AFFINITY_MODE dwFlags);

	/// <summary>Sets the default CPU Sets assignment for threads in the specified process.</summary>
	/// <param name="Process">
	/// Specifies the process for which to set the default CPU Sets. This handle must have the PROCESS_SET_LIMITED_INFORMATION access right.
	/// The value returned by GetCurrentProcess can also be specified here.
	/// </param>
	/// <param name="CpuSetMasks">
	/// Specifies an optional buffer of GROUP_AFFINITY structures representing the CPU Sets to set as the process default CPU set. If this is
	/// NULL, the <c>SetProcessDefaultCpuSetMasks</c> function clears out any assignment.
	/// </param>
	/// <param name="CpuSetMaskCount">
	/// Specifies the size of the CpuSetMasks array, in elements. If the buffer is NULL, this value must be zero.
	/// </param>
	/// <returns>This function cannot fail when passed valid parameters.</returns>
	/// <remarks>
	/// <para>
	/// Threads belonging to this process which don’t have CPU Sets explicitly set using SetThreadSelectedCpuSetMasks or
	/// SetThreadSelectedCpuSets, will inherit the sets specified by <c>SetProcessDefaultCpuSetMasks</c> automatically.
	/// </para>
	/// <para>
	/// This function is analogous to SetProcessDefaultCpuSets, except that it uses group affinities as opposed to CPU Set IDs to represent a
	/// list of CPU sets. This means that the resulting process default CPU Set assignment is the set of all CPU sets with a home processor
	/// in the provided list of group affinities.
	/// </para>
	/// </remarks>
	// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setprocessdefaultcpusetmasks BOOL
	// SetProcessDefaultCpuSetMasks( HANDLE Process, PGROUP_AFFINITY CpuSetMasks, USHORT CpuSetMaskCount );
	[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
	[PInvokeData("processthreadsapi.h", MSDNShortId = "NF:processthreadsapi.SetProcessDefaultCpuSetMasks")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool SetProcessDefaultCpuSetMasks([In, AddAsMember] HPROCESS Process,
		[In, Optional, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] GROUP_AFFINITY[]? CpuSetMasks, [Optional] ushort CpuSetMaskCount);

	/// <summary>
	/// Sets the default CPU Sets assignment for threads in the specified process. Threads that are created, which don’t have CPU Sets
	/// explicitly set using <c>SetThreadSelectedCpuSets</c>, will inherit the sets specified by <c>SetProcessDefaultCpuSets</c> automatically.
	/// </summary>
	/// <param name="Process">
	/// Specifies the process for which to set the default CPU Sets. This handle must have the PROCESS_SET_LIMITED_INFORMATION access right.
	/// The value returned by <c>GetCurrentProcess</c> can also be specified here.
	/// </param>
	/// <param name="CpuSetIds">
	/// Specifies the list of CPU Set IDs to set as the process default CPU set. If this is NULL, the <c>SetProcessDefaultCpuSets</c> clears
	/// out any assignment.
	/// </param>
	/// <param name="CpuSetIdCound">
	/// Specifies the number of IDs in the list passed in the <c>CpuSetIds</c> argument. If that value is NULL, this should be 0.
	/// </param>
	/// <returns>This function cannot fail when passed valid parameters.</returns>
	// BOOL WINAPI SetProcessDefaultCpuSets( _In_ HANDLE Process, _In_opt_ ULONG CpuSetIds, _In_ ULONG CpuSetIdCound); https://msdn.microsoft.com/en-us/library/windows/desktop/mt186427(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
	[PInvokeData("Processthreadapi.h", MSDNShortId = "mt186427")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool SetProcessDefaultCpuSets([In, AddAsMember] HPROCESS Process, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] uint[]? CpuSetIds, uint CpuSetIdCound);

	/// <summary>Sets dynamic exception handling continuation targets for the specified process.</summary>
	/// <param name="Process">
	/// A handle to the process. This handle must have the <c>PROCESS_SET_INFORMATION</c> access right. For more information, see Process
	/// Security and Access Rights.
	/// </param>
	/// <param name="NumberOfTargets">Supplies the number of dynamic exception handling continuation targets to set.</param>
	/// <param name="Targets">
	/// A pointer to an array of dynamic exception handling continuation targets. For more information on this structure, see PROCESS_DYNAMIC_EH_CONTINUATION_TARGET.
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>
	/// If the function fails, the return value is zero. To get extended error information, call GetLastError. Note that even if the function
	/// fails, a portion of the supplied continuation targets may have been successfully processed. The caller needs to check the flags in
	/// each individual continuation target specified via Targets to determine if it was successfully processed.
	/// </para>
	/// </returns>
	/// <remarks>
	/// If user-mode Hardware-enforced Stack Protection is enabled for a process, when calling APIs that modify the execution context of a
	/// thread such as RtlRestoreContext and SetThreadContext, validation is performed on the Instruction Pointer specified in the new
	/// execution context. RtlRestoreContext is used during Structured Exception Handling (SEH) exception unwinding to unwind to the target
	/// frame that contains the <c>__except</c> block and to start executing code at the continuation target. Therefore, the operating system
	/// needs to know the instruction addresses of all the valid continuation targets in order to allow the unwind operation via
	/// RtlRestoreContext. For compiled binaries, the list of continuation targets is generated by the linker and stored in the binary image.
	/// For dynamic code, the continuation targets need to be specified using SetProcessDynamicEHContinuationTargets.
	/// </remarks>
	// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setprocessdynamicehcontinuationtargets BOOL
	// SetProcessDynamicEHContinuationTargets( HANDLE Process, USHORT NumberOfTargets, PPROCESS_DYNAMIC_EH_CONTINUATION_TARGET Targets );
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("processthreadsapi.h", MSDNShortId = "NF:processthreadsapi.SetProcessDynamicEHContinuationTargets")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool SetProcessDynamicEHContinuationTargets([In] HPROCESS Process, ushort NumberOfTargets, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] PROCESS_DYNAMIC_EH_CONTINUATION_TARGET[] Targets);

	/// <summary>Sets information for the specified process.</summary>
	/// <param name="hProcess">
	/// A handle to the process. This handle must have the <c>PROCESS_SET_INFORMATION</c> access right. For more information, see Process
	/// Security and Access Rights.
	/// </param>
	/// <param name="ProcessInformationClass">
	/// The class of information to set. The only supported values are <c>ProcessMemoryPriority</c> and <c>ProcessPowerThrottling</c>.
	/// </param>
	/// <param name="ProcessInformation">
	/// <para>Pointer to an object that contains the type of information specified by the ProcessInformationClass parameter.</para>
	/// <para>
	/// If the ProcessInformationClass parameter is <c>ProcessMemoryPriority</c>, this parameter must point to a
	/// <c>MEMORY_PRIORITY_INFORMATION</c> structure.
	/// </para>
	/// <para>
	/// If the ProcessInformationClass parameter is <c>ProcessPowerThrottling</c>, this parameter must point to a
	/// <c>PROCESS_POWER_THROTTLING_STATE</c> structure.
	/// </para>
	/// </param>
	/// <param name="ProcessInformationSize">
	/// <para>The size in bytes of the structure specified by the ProcessInformation parameter.</para>
	/// <para>If the ProcessInformationClass parameter is <c>ProcessMemoryPriority</c>, this parameter must be .</para>
	/// <para>If the ProcessInformationClass parameter is <c>ProcessPowerThrottling</c>, this parameter must be .</para>
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// BOOL WINAPI SetProcessInformation( _In_ HANDLE hProcess, _In_ PROCESS_INFORMATION_CLASS ProcessInformationClass,
	// _In_reads_bytes_(ProcessInformationSize) ProcessInformation, _In_ DWORD ProcessInformationSize); https://msdn.microsoft.com/en-us/library/windows/desktop/hh448389(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "hh448389")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool SetProcessInformation([In] HPROCESS hProcess, PROCESS_INFORMATION_CLASS ProcessInformationClass, IntPtr ProcessInformation, uint ProcessInformationSize);

	/// <summary>Sets information for the specified process.</summary>
	/// <param name="hProcess">
	/// A handle to the process. This handle must have the <c>PROCESS_SET_INFORMATION</c> access right. For more information, see Process
	/// Security and Access Rights.
	/// </param>
	/// <param name="ProcessInformationClass">
	/// The class of information to set. The only supported values are <c>ProcessMemoryPriority</c> and <c>ProcessPowerThrottling</c>.
	/// </param>
	/// <param name="ProcessInformation">
	/// <para>Pointer to an object that contains the type of information specified by the ProcessInformationClass parameter.</para>
	/// <para>
	/// If the ProcessInformationClass parameter is <c>ProcessMemoryPriority</c>, this parameter must point to a
	/// <c>MEMORY_PRIORITY_INFORMATION</c> structure.
	/// </para>
	/// <para>
	/// If the ProcessInformationClass parameter is <c>ProcessPowerThrottling</c>, this parameter must point to a
	/// <c>PROCESS_POWER_THROTTLING_STATE</c> structure.
	/// </para>
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	[PInvokeData("WinBase.h", MSDNShortId = "hh448389")]
	public static bool SetProcessInformation<T>([In, AddAsMember] HPROCESS hProcess, PROCESS_INFORMATION_CLASS ProcessInformationClass, in T ProcessInformation) where T : struct
	{
		if (!CorrespondingTypeAttribute.CanSet(ProcessInformationClass, typeof(T))) throw new ArgumentException($"{ProcessInformationClass} cannot be used to set values of type {typeof(T)}.");
		using SafeHGlobalHandle mem = SafeHGlobalHandle.CreateFromStructure(ProcessInformation);
		return SetProcessInformation(hProcess, ProcessInformationClass, (IntPtr)mem, (uint)mem.Size);
	}

	/// <summary>
	/// Sets a mitigation policy for the calling process. Mitigation policies enable a process to harden itself against various types of attacks.
	/// </summary>
	/// <param name="MitigationPolicy">
	/// <para>The mitigation policy to apply. This parameter can be one of the following values.</para>
	/// <para>
	/// <list type="table">
	/// <listheader>
	/// <term>Value</term>
	/// <term>Meaning</term>
	/// </listheader>
	/// <item>
	/// <term>ProcessDEPPolicy</term>
	/// <term>
	/// The data execution prevention (DEP) policy of the process.The lpBuffer parameter points to a PROCESS_MITIGATION_DEP_POLICY structure
	/// that specifies the DEP policy flags.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessASLRPolicy</term>
	/// <term>
	/// The Address Space Layout Randomization (ASLR) policy of the process.The lpBuffer parameter points to a PROCESS_MITIGATION_ASLR_POLICY
	/// structure that specifies the ASLR policy flags.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessDynamicCodePolicy</term>
	/// <term>
	/// The dynamic code policy of the process. When turned on, the process cannot generate dynamic code or modify existing executable
	/// code.The lpBuffer parameter points to a PROCESS_MITIGATION_DYNAMIC_CODE_POLICY structure that specifies the dynamic code policy flags.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessStrictHandleCheckPolicy</term>
	/// <term>
	/// The process will receive a fatal error if it manipulates a handle that is not valid.The lpBuffer parameter points to a
	/// PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY structure that specifies the handle check policy flags.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessSystemCallDisablePolicy</term>
	/// <term>
	/// Disables the ability to use NTUser/GDI functions at the lowest layer.The lpBuffer parameter points to a
	/// PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY structure that specifies the system call disable policy flags.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessMitigationOptionsMask</term>
	/// <term>
	/// Returns the mask of valid bits for all the mitigation options on the system. An application can set many mitigation options without
	/// querying the operating system for mitigation options by combining bitwise with the mask to exclude all non-supported bits at once.The
	/// lpBuffer parameter points to a ULONG64 bit vector for the mask, or to accommodate more than 64 bits, a two-element array of ULONG64
	/// bit vectors.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessExtensionPointDisablePolicy</term>
	/// <term>
	/// The lpBuffer parameter points to a PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY structure that specifies the extension point
	/// disable policy flags.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessControlFlowGuardPolicy</term>
	/// <term>
	/// The Control Flow Guard (CFG) policy of the process.The lpBuffer parameter points to a PROCESS_MITIGATION_CONTROL_FLOW_GUARD_POLICY
	/// structure that specifies the CFG policy flags.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessSignaturePolicy</term>
	/// <term>
	/// The policy of a process that can restrict image loading to those images that are either signed by Microsoft, by the Windows Store, or
	/// by Microsoft, the Windows Store and the Windows Hardware Quality Labs (WHQL).he lpBuffer parameter points to a
	/// PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY structure that specifies the signature policy flags.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessFontDisablePolicy</term>
	/// <term>
	/// The policy regarding font loading for the process. When turned on, the process cannot load non-system fonts.The lpBuffer parameter
	/// points to a PROCESS_MITIGATION_FONT_DISABLE_POLICY structure that specifies the policy flags for font loading.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessImageLoadPolicy</term>
	/// <term>
	/// The policy regarding image loading for the process, which determines the types of executable images that are allowed to be mapped
	/// into the process. When turned on, images cannot be loaded from some locations, such a remote devices or files that have the low
	/// mandatory label.The lpBuffer parameter points to a PROCESS_MITIGATION_IMAGE_LOAD_POLICY structure that specifies the policy flags for
	/// image loading.
	/// </term>
	/// </item>
	/// </list>
	/// </para>
	/// </param>
	/// <param name="lpBuffer">
	/// <para>
	/// If the MitigationPolicy parameter is <c>ProcessDEPPolicy</c>, this parameter points to a <c>PROCESS_MITIGATION_DEP_POLICY</c>
	/// structure that specifies the DEP policy flags.
	/// </para>
	/// <para>
	/// If the MitigationPolicy parameter is <c>ProcessASLRPolicy</c>, this parameter points to a <c>PROCESS_MITIGATION_ASLR_POLICY</c>
	/// structure that specifies the ASLR policy flags.
	/// </para>
	/// <para>
	/// If the MitigationPolicy parameter is <c>ProcessImageLoadPolicy</c>, this parameter points to a
	/// <c>PROCESS_MITIGATION_IMAGE_LOAD_POLICY</c> structure that receives the policy flags for image loading.
	/// </para>
	/// <para>
	/// If the MitigationPolicy parameter is <c>ProcessStrictHandleCheckPolicy</c>, this parameter points to a
	/// <c>PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY</c> structure that specifies the handle check policy flags.
	/// </para>
	/// <para>
	/// If the MitigationPolicy parameter is <c>ProcessSystemCallDisablePolicy</c>, this parameter points to a
	/// <c>PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY</c> structure that specifies the system call disable policy flags.
	/// </para>
	/// <para>
	/// If the MitigationPolicy parameter is <c>ProcessMitigationOptionsMask</c>, this parameter points to a <c>ULONG64</c> bit vector for
	/// the mask, or to accommodate more than 64 bits, a two-element array of <c>ULONG64</c> bit vectors.
	/// </para>
	/// <para>
	/// If the MitigationPolicy parameter is <c>ProcessExtensionPointDisablePolicy</c>, this parameter points to a
	/// <c>PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY</c> structure that specifies the extension point disable policy flags.
	/// </para>
	/// <para>
	/// If the MitigationPolicy parameter is <c>ProcessControlFlowGuardPolicy</c>, this parameter points to a
	/// <c>PROCESS_MITIGATION_CONTROL_FLOW_GUARD_POLICY</c> structure that specifies the CFG policy flags.
	/// </para>
	/// <para>
	/// If the MitigationPolicy parameter is <c>ProcessSignaturePolicy</c>, this parameter points to a
	/// <c>PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY</c> structure that specifies the signature policy flags.
	/// </para>
	/// <para>
	/// If the MitigationPolicy parameter is <c>ProcessFontDisablePolicy</c>, this parameter points to a
	/// <c>PROCESS_MITIGATION_FONT_DISABLE_POLICY</c> structure that specifies the policy flags for font loading.
	/// </para>
	/// <para>
	/// If the MitigationPolicy parameter is <c>ProcessImageLoadPolicy</c>, this parameter points to a
	/// <c>PROCESS_MITIGATION_IMAGE_LOAD_POLICY</c> structure that specifies the policy flags for image loading.
	/// </para>
	/// </param>
	/// <param name="dwLength">The size of lpBuffer, in bytes.</param>
	/// <returns>
	/// If the function succeeds, it returns <c>TRUE</c>. If the function fails, it returns <c>FALSE</c>. To retrieve error values defined
	/// for this function, call <c>GetLastError</c>.
	/// </returns>
	// BOOL WINAPI SetProcessMitigationPolicy( _In_ PROCESS_MITIGATION_POLICY MitigationPolicy, _In_ PVOID lpBuffer, _In_ SIZE_T dwLength); https://msdn.microsoft.com/en-us/library/windows/desktop/hh769088(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("Processthreadsapi.h", MSDNShortId = "hh769088")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool SetProcessMitigationPolicy(PROCESS_MITIGATION_POLICY MitigationPolicy, IntPtr lpBuffer, SizeT dwLength);

	/// <summary>
	/// Sets a mitigation policy for the calling process. Mitigation policies enable a process to harden itself against various types of attacks.
	/// </summary>
	/// <typeparam name="T">The type of the value being set.</typeparam>
	/// <param name="MitigationPolicy">
	/// <para>The mitigation policy to apply. This parameter can be one of the following values.</para>
	/// <para>
	/// <list type="table">
	/// <listheader>
	/// <term>Value</term>
	/// <term>Meaning</term>
	/// </listheader>
	/// <item>
	/// <term>ProcessDEPPolicy</term>
	/// <term>
	/// The data execution prevention (DEP) policy of the process.The lpBuffer parameter points to a PROCESS_MITIGATION_DEP_POLICY structure
	/// that specifies the DEP policy flags.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessASLRPolicy</term>
	/// <term>
	/// The Address Space Layout Randomization (ASLR) policy of the process.The lpBuffer parameter points to a PROCESS_MITIGATION_ASLR_POLICY
	/// structure that specifies the ASLR policy flags.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessDynamicCodePolicy</term>
	/// <term>
	/// The dynamic code policy of the process. When turned on, the process cannot generate dynamic code or modify existing executable
	/// code.The lpBuffer parameter points to a PROCESS_MITIGATION_DYNAMIC_CODE_POLICY structure that specifies the dynamic code policy flags.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessStrictHandleCheckPolicy</term>
	/// <term>
	/// The process will receive a fatal error if it manipulates a handle that is not valid.The lpBuffer parameter points to a
	/// PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY structure that specifies the handle check policy flags.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessSystemCallDisablePolicy</term>
	/// <term>
	/// Disables the ability to use NTUser/GDI functions at the lowest layer.The lpBuffer parameter points to a
	/// PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY structure that specifies the system call disable policy flags.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessMitigationOptionsMask</term>
	/// <term>
	/// Returns the mask of valid bits for all the mitigation options on the system. An application can set many mitigation options without
	/// querying the operating system for mitigation options by combining bitwise with the mask to exclude all non-supported bits at once.The
	/// lpBuffer parameter points to a ULONG64 bit vector for the mask, or to accommodate more than 64 bits, a two-element array of ULONG64
	/// bit vectors.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessExtensionPointDisablePolicy</term>
	/// <term>
	/// The lpBuffer parameter points to a PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY structure that specifies the extension point
	/// disable policy flags.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessControlFlowGuardPolicy</term>
	/// <term>
	/// The Control Flow Guard (CFG) policy of the process.The lpBuffer parameter points to a PROCESS_MITIGATION_CONTROL_FLOW_GUARD_POLICY
	/// structure that specifies the CFG policy flags.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessSignaturePolicy</term>
	/// <term>
	/// The policy of a process that can restrict image loading to those images that are either signed by Microsoft, by the Windows Store, or
	/// by Microsoft, the Windows Store and the Windows Hardware Quality Labs (WHQL).he lpBuffer parameter points to a
	/// PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY structure that specifies the signature policy flags.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessFontDisablePolicy</term>
	/// <term>
	/// The policy regarding font loading for the process. When turned on, the process cannot load non-system fonts.The lpBuffer parameter
	/// points to a PROCESS_MITIGATION_FONT_DISABLE_POLICY structure that specifies the policy flags for font loading.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ProcessImageLoadPolicy</term>
	/// <term>
	/// The policy regarding image loading for the process, which determines the types of executable images that are allowed to be mapped
	/// into the process. When turned on, images cannot be loaded from some locations, such a remote devices or files that have the low
	/// mandatory label.The lpBuffer parameter points to a PROCESS_MITIGATION_IMAGE_LOAD_POLICY structure that specifies the policy flags for
	/// image loading.
	/// </term>
	/// </item>
	/// </list>
	/// </para>
	/// </param>
	/// <param name="value">The value. This must correspond to the <paramref name="MitigationPolicy"/> value.</param>
	/// <returns>
	/// If the function succeeds, it returns <c>TRUE</c>. If the function fails, it returns <c>FALSE</c>. To retrieve error values defined
	/// for this function, call <c>GetLastError</c>.
	/// </returns>
	public static bool SetProcessMitigationPolicy<T>(PROCESS_MITIGATION_POLICY MitigationPolicy, in T value)
	{
		if (MitigationPolicy == PROCESS_MITIGATION_POLICY.ProcessMitigationOptionsMask)
		{
			if (!(value is ulong || value is ulong[])) throw new ArgumentException($"{MitigationPolicy} cannot be used to set values of type {typeof(T)}.");
			using PinnedObject ptr = new(value);
			return SetProcessMitigationPolicy(MitigationPolicy, ptr, value is ulong ? 8U : 16U);
		}

		if (!CorrespondingTypeAttribute.CanSet(MitigationPolicy, typeof(T))) throw new ArgumentException($"{MitigationPolicy} cannot be used to set values of type {typeof(T)}.");
		using (SafeCoTaskMemHandle ptr = SafeCoTaskMemHandle.CreateFromStructure(value))
			return SetProcessMitigationPolicy(MitigationPolicy, (IntPtr)ptr, (uint)ptr.Size);
	}

	/// <summary>Disables or enables the ability of the system to temporarily boost the priority of the threads of the specified process.</summary>
	/// <param name="hProcess">
	/// A handle to the process. This handle must have the PROCESS_SET_INFORMATION access right. For more information, see Process Security
	/// and Access Rights.
	/// </param>
	/// <param name="DisablePriorityBoost">
	/// If this parameter is TRUE, dynamic boosting is disabled. If the parameter is FALSE, dynamic boosting is enabled.
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// BOOL WINAPI SetProcessPriorityBoost( _In_ HANDLE hProcess, _In_ BOOL DisablePriorityBoost); https://msdn.microsoft.com/en-us/library/windows/desktop/ms686225(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms686225")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool SetProcessPriorityBoost([In, AddAsMember] HPROCESS hProcess, [MarshalAs(UnmanagedType.Bool)] bool DisablePriorityBoost);

	/// <summary>
	/// Sets shutdown parameters for the currently calling process. This function sets a shutdown order for a process relative to the other
	/// processes in the system.
	/// </summary>
	/// <param name="dwLevel">
	/// <para>
	/// The shutdown priority for a process relative to other processes in the system. The system shuts down processes from high dwLevel
	/// values to low. The highest and lowest shutdown priorities are reserved for system components. This parameter must be in the following
	/// range of values.
	/// </para>
	/// <para>
	/// <list type="table">
	/// <listheader>
	/// <term>Value</term>
	/// <term>Meaning</term>
	/// </listheader>
	/// <item>
	/// <term>000-0FF</term>
	/// <term>System reserved last shutdown range.</term>
	/// </item>
	/// <item>
	/// <term>100-1FF</term>
	/// <term>Application reserved last shutdown range.</term>
	/// </item>
	/// <item>
	/// <term>200-2FF</term>
	/// <term>Application reserved &amp;quot;in between&amp;quot; shutdown range.</term>
	/// </item>
	/// <item>
	/// <term>300-3FF</term>
	/// <term>Application reserved first shutdown range.</term>
	/// </item>
	/// <item>
	/// <term>400-4FF</term>
	/// <term>System reserved first shutdown range.</term>
	/// </item>
	/// </list>
	/// </para>
	/// <para>All processes start at shutdown level 0x280.</para>
	/// </param>
	/// <param name="dwFlags">
	/// <para>This parameter can be the following value.</para>
	/// <para>
	/// <list type="table">
	/// <listheader>
	/// <term>Value</term>
	/// <term>Meaning</term>
	/// </listheader>
	/// <item>
	/// <term>SHUTDOWN_NORETRY0x00000001</term>
	/// <term>The system terminates the process without displaying a retry dialog box for the user.</term>
	/// </item>
	/// </list>
	/// </para>
	/// </param>
	/// <returns>
	/// <para>If the function is succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// BOOL WINAPI SetProcessShutdownParameters( _In_ DWORD dwLevel, _In_ DWORD dwFlags); https://msdn.microsoft.com/en-us/library/windows/desktop/ms686227(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms686227")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool SetProcessShutdownParameters(uint dwLevel, SHUTDOWN dwFlags);

	/// <summary>Sets a protected policy. This function is for use primarily by Windows, and not designed for external use.</summary>
	/// <param name="PolicyGuid">The globally-unique identifier of the policy to set.</param>
	/// <param name="PolicyValue">The value to set the policy to.</param>
	/// <param name="OldPolicyValue">Optionally receives the original value that was associated with the supplied policy.</param>
	/// <returns>True if the function succeeds; otherwise, false. To retrieve error values for this function, call <c>GetLastError</c>.</returns>
	// BOOL WINAPI SetProtectedPolicy( _In_ LPCGUID PolicyGuid, _In_ ULONG_PTR PolicyValue, _Out_ PULONG_PTR OldPolicyValue); https://msdn.microsoft.com/en-us/library/windows/desktop/dn893592(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("Winbase.h", MSDNShortId = "dn893592")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool SetProtectedPolicy(in Guid PolicyGuid, IntPtr PolicyValue, out IntPtr OldPolicyValue);

	/// <summary>
	/// <para>Sets the context for the specified thread.</para>
	/// <para>A 64-bit application can set the context of a WOW64 thread using the <c>Wow64SetThreadContext</c> function.</para>
	/// </summary>
	/// <param name="hThread">
	/// A handle to the thread whose context is to be set. The handle must have the <c>THREAD_SET_CONTEXT</c> access right to the thread. For
	/// more information, see Thread Security and Access Rights.
	/// </param>
	/// <param name="lpContext">
	/// A pointer to a <c>CONTEXT</c> structure that contains the context to be set in the specified thread. The value of the
	/// <c>ContextFlags</c> member of this structure specifies which portions of a thread's context to set. Some values in the <c>CONTEXT</c>
	/// structure that cannot be specified are silently set to the correct value. This includes bits in the CPU status register that specify
	/// the privileged processor mode, global enabling bits in the debugging register, and other states that must be controlled by the
	/// operating system.
	/// </param>
	/// <returns>
	/// <para>If the context was set, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// BOOL WINAPI SetThreadContext( _In_ HANDLE hThread, _In_ const CONTEXT *lpContext); https://msdn.microsoft.com/en-us/library/windows/desktop/ms680632(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms680632")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool SetThreadContext([In, AddAsMember] HTHREAD hThread, in CONTEXT lpContext);

	/// <summary>Assigns a description to a thread.</summary>
	/// <param name="hThread">
	/// A handle for the thread for which you want to set the description. The handle must have THREAD_SET_LIMITED_INFORMATION access.
	/// </param>
	/// <param name="lpThreadDescription">A Unicode string that specifies the description of the thread.</param>
	/// <returns>
	/// If the function succeeds, the return value is the <c>HRESULT</c> that denotes a successful operation.If the function fails, the
	/// return value is an <c>HRESULT</c> that denotes the error.
	/// </returns>
	// HRESULT WINAPI SetThreadDescription( _In_ HANDLE hThread, _In_ PCWSTR lpThreadDescription); https://msdn.microsoft.com/en-us/library/windows/desktop/mt774976(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
	[PInvokeData("ProcessThreadsApi.h", MSDNShortId = "mt774976")]
	public static extern HRESULT SetThreadDescription([In, AddAsMember] HTHREAD hThread, [MarshalAs(UnmanagedType.LPWStr)] string lpThreadDescription);

	/// <summary>
	/// <para>Sets a preferred processor for a thread. The system schedules threads on their preferred processors whenever possible.</para>
	/// <para>
	/// On a system with more than 64 processors, this function sets the preferred processor to a logical processor in the processor group to
	/// which the calling thread is assigned. Use the <c>SetThreadIdealProcessorEx</c> function to specify a processor group and preferred processor.
	/// </para>
	/// </summary>
	/// <param name="hThread">
	/// A handle to the thread whose preferred processor is to be set. The handle must have the THREAD_SET_INFORMATION access right. For more
	/// information, see Thread Security and Access Rights.
	/// </param>
	/// <param name="dwIdealProcessor">
	/// The number of the preferred processor for the thread. This value is zero-based. If this parameter is MAXIMUM_PROCESSORS, the function
	/// returns the current ideal processor without changing it.
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is the previous preferred processor.</para>
	/// <para>If the function fails, the return value is (DWORD) – 1. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// DWORD WINAPI SetThreadIdealProcessor( _In_ HANDLE hThread, _In_ DWORD dwIdealProcessor); https://msdn.microsoft.com/en-us/library/windows/desktop/ms686253(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms686253")]
	public static extern uint SetThreadIdealProcessor([In] HTHREAD hThread, uint dwIdealProcessor);

	/// <summary>Sets the ideal processor for the specified thread and optionally retrieves the previous ideal processor.</summary>
	/// <param name="hThread">
	/// A handle to the thread for which to set the ideal processor. This handle must have been created with the THREAD_SET_INFORMATION
	/// access right. For more information, see Thread Security and Access Rights.
	/// </param>
	/// <param name="lpIdealProcessor">
	/// A pointer to a PROCESSOR_NUMBER structure that specifies the processor number of the desired ideal processor.
	/// </param>
	/// <param name="lpPreviousIdealProcessor">
	/// A pointer to a PROCESSOR_NUMBER structure to receive the previous ideal processor. This parameter can point to the same memory
	/// location as the lpIdealProcessor parameter. This parameter can be NULL if the previous ideal processor is not required.
	/// </param>
	/// <returns>
	/// If the function succeeds, it returns a nonzero value. If the function fails, it returns zero.To get extended error information, use GetLastError.
	/// </returns>
	// https://msdn.microsoft.com/en-us/library/windows/desktop/dd405517(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "dd405517")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool SetThreadIdealProcessorEx([In, AddAsMember] HTHREAD hThread, in PROCESSOR_NUMBER lpIdealProcessor, out PROCESSOR_NUMBER lpPreviousIdealProcessor);

	/// <summary>Sets information for the specified thread.</summary>
	/// <param name="hThread">
	/// A handle to the thread. The handle must have THREAD_QUERY_INFORMATION access right. For more information, see Thread Security and
	/// Access Rights.
	/// </param>
	/// <param name="ThreadInformationClass">
	/// The class of information to set. The only supported values are <c>ThreadMemoryPriority</c> and <c>ThreadPowerThrottling</c>.
	/// </param>
	/// <param name="ThreadInformation">
	/// <para>Pointer to a structure that contains the type of information specified by the ThreadInformationClass parameter.</para>
	/// <para>
	/// If the ThreadInformationClass parameter is <c>ThreadMemoryPriority</c>, this parameter must point to a
	/// <c>MEMORY_PRIORITY_INFORMATION</c> structure.
	/// </para>
	/// <para>
	/// If the ThreadInformationClass parameter is <c>ThreadPowerThrottling</c>, this parameter must point to a
	/// <c>THREAD_POWER_THROTTLING_STATE</c> structure.
	/// </para>
	/// </param>
	/// <param name="ThreadInformationSize">
	/// <para>The size in bytes of the structure specified by the ThreadInformation parameter.</para>
	/// <para>If the ThreadInformationClass parameter is <c>ThreadMemoryPriority</c>, this parameter must be .</para>
	/// <para>If the ThreadInformationClass parameter is <c>ThreadPowerThrottling</c>, this parameter must be .</para>
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call GetLastError.</para>
	/// </returns>
	/// <remarks>
	/// <para>
	/// To help improve system performance, applications should use the <c>SetThreadInformation</c> function with <c>ThreadMemoryPriority</c>
	/// to lower the memory priority of threads that perform background operations or access files and data that are not expected to be
	/// accessed again soon. For example, an anti-malware application might lower the priority of threads involved in scanning files.
	/// </para>
	/// <para>
	/// Memory priority helps to determine how long pages remain in the working set of a process before they are trimmed. A thread's memory
	/// priority determines the minimum priority of the physical pages that are added to the process working set by that thread. When the
	/// memory manager trims the working set, it trims lower priority pages before higher priority pages. This improves overall system
	/// performance because higher priority pages are less likely to be trimmed from the working set and then trigger a page fault when they
	/// are accessed again.
	/// </para>
	/// <para>Examples</para>
	/// <para>
	/// The following example shows how to call <c>SetThreadInformation</c> with <c>ThreadMemoryPriority</c> to set low memory priority on
	/// the current thread.
	/// </para>
	/// <para>
	/// The following example shows how to call <c>SetThreadInformation</c> with <c>ThreadPowerThrottling</c> to enable throttling policies
	/// on a thread.
	/// </para>
	/// </remarks>
	// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreadinformation BOOL
	// SetThreadInformation( HANDLE hThread, THREAD_INFORMATION_CLASS ThreadInformationClass, LPVOID ThreadInformation, DWORD
	// ThreadInformationSize );
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("processthreadsapi.h", MSDNShortId = "c0159bea-870a-46b7-a350-91fe52efae49")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool SetThreadInformation(HTHREAD hThread, THREAD_INFORMATION_CLASS ThreadInformationClass, IntPtr ThreadInformation, uint ThreadInformationSize);

	/// <summary>Sets information for the specified thread.</summary>
	/// <typeparam name="T">
	/// The type of the structure that contains the type of information specified by the ThreadInformationClass parameter.
	/// </typeparam>
	/// <param name="hThread">
	/// A handle to the thread. The handle must have THREAD_QUERY_INFORMATION access right. For more information, see Thread Security and
	/// Access Rights.
	/// </param>
	/// <param name="ThreadInformationClass">
	/// The class of information to set. The only supported values are <c>ThreadMemoryPriority</c> and <c>ThreadPowerThrottling</c>.
	/// </param>
	/// <param name="ThreadInformation">
	/// <para>The structure that contains the type of information specified by the ThreadInformationClass parameter.</para>
	/// <para>
	/// If the ThreadInformationClass parameter is <c>ThreadMemoryPriority</c>, this parameter must point to a
	/// <c>MEMORY_PRIORITY_INFORMATION</c> structure.
	/// </para>
	/// <para>
	/// If the ThreadInformationClass parameter is <c>ThreadPowerThrottling</c>, this parameter must point to a
	/// <c>THREAD_POWER_THROTTLING_STATE</c> structure.
	/// </para>
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call GetLastError.</para>
	/// </returns>
	/// <exception cref="ArgumentException"></exception>
	/// <remarks>
	/// <para>
	/// To help improve system performance, applications should use the <c>SetThreadInformation</c> function with <c>ThreadMemoryPriority</c>
	/// to lower the memory priority of threads that perform background operations or access files and data that are not expected to be
	/// accessed again soon. For example, an anti-malware application might lower the priority of threads involved in scanning files.
	/// </para>
	/// <para>
	/// Memory priority helps to determine how long pages remain in the working set of a process before they are trimmed. A thread's memory
	/// priority determines the minimum priority of the physical pages that are added to the process working set by that thread. When the
	/// memory manager trims the working set, it trims lower priority pages before higher priority pages. This improves overall system
	/// performance because higher priority pages are less likely to be trimmed from the working set and then trigger a page fault when they
	/// are accessed again.
	/// </para>
	/// <para>Examples</para>
	/// <para>
	/// The following example shows how to call <c>SetThreadInformation</c> with <c>ThreadMemoryPriority</c> to set low memory priority on
	/// the current thread.
	/// </para>
	/// <para>
	/// The following example shows how to call <c>SetThreadInformation</c> with <c>ThreadPowerThrottling</c> to enable throttling policies
	/// on a thread.
	/// </para>
	/// </remarks>
	[PInvokeData("processthreadsapi.h", MSDNShortId = "c0159bea-870a-46b7-a350-91fe52efae49")]
	public static bool SetThreadInformation<T>([In, AddAsMember] HTHREAD hThread, THREAD_INFORMATION_CLASS ThreadInformationClass, in T ThreadInformation)
	{
		if (!CorrespondingTypeAttribute.CanSet(ThreadInformationClass, typeof(T))) throw new ArgumentException($"{ThreadInformationClass} cannot be used to set values of type {typeof(T)}.");
		using SafeHGlobalHandle mem = SafeHGlobalHandle.CreateFromStructure(ThreadInformation);
		return SetThreadInformation(hThread, ThreadInformationClass, (IntPtr)mem, (uint)mem.Size);
	}

	/// <summary>
	/// Sets the priority value for the specified thread. This value, together with the priority class of the thread's process, determines
	/// the thread's base priority level.
	/// </summary>
	/// <param name="hThread">
	/// <para>A handle to the thread whose priority value is to be set.</para>
	/// <para>
	/// The handle must have the <c>THREAD_SET_INFORMATION</c> or <c>THREAD_SET_LIMITED_INFORMATION</c> access right. For more information,
	/// see Thread Security and Access Rights.
	/// </para>
	/// <para><c>Windows Server 2003:</c> The handle must have the <c>THREAD_SET_INFORMATION</c> access right.</para>
	/// </param>
	/// <param name="nPriority">
	/// <para>The priority value for the thread. This parameter can be one of the following values.</para>
	/// <para>
	/// <list type="table">
	/// <listheader>
	/// <term>Priority</term>
	/// <term>Meaning</term>
	/// </listheader>
	/// <item>
	/// <term>THREAD_MODE_BACKGROUND_BEGIN0x00010000</term>
	/// <term>
	/// Begin background processing mode. The system lowers the resource scheduling priorities of the thread so that it can perform
	/// background work without significantly affecting activity in the foreground.This value can be specified only if hThread is a handle to
	/// the current thread. The function fails if the thread is already in background processing mode.Windows Server 2003: This value is not supported.
	/// </term>
	/// </item>
	/// <item>
	/// <term>THREAD_MODE_BACKGROUND_END0x00020000</term>
	/// <term>
	/// End background processing mode. The system restores the resource scheduling priorities of the thread as they were before the thread
	/// entered background processing mode.This value can be specified only if hThread is a handle to the current thread. The function fails
	/// if the thread is not in background processing mode.Windows Server 2003: This value is not supported.
	/// </term>
	/// </item>
	/// <item>
	/// <term>THREAD_PRIORITY_ABOVE_NORMAL1</term>
	/// <term>Priority 1 point above the priority class.</term>
	/// </item>
	/// <item>
	/// <term>THREAD_PRIORITY_BELOW_NORMAL-1</term>
	/// <term>Priority 1 point below the priority class.</term>
	/// </item>
	/// <item>
	/// <term>THREAD_PRIORITY_HIGHEST2</term>
	/// <term>Priority 2 points above the priority class.</term>
	/// </item>
	/// <item>
	/// <term>THREAD_PRIORITY_IDLE-15</term>
	/// <term>
	/// Base priority of 1 for IDLE_PRIORITY_CLASS, BELOW_NORMAL_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, ABOVE_NORMAL_PRIORITY_CLASS, or
	/// HIGH_PRIORITY_CLASS processes, and a base priority of 16 for REALTIME_PRIORITY_CLASS processes.
	/// </term>
	/// </item>
	/// <item>
	/// <term>THREAD_PRIORITY_LOWEST-2</term>
	/// <term>Priority 2 points below the priority class.</term>
	/// </item>
	/// <item>
	/// <term>THREAD_PRIORITY_NORMAL0</term>
	/// <term>Normal priority for the priority class.</term>
	/// </item>
	/// <item>
	/// <term>THREAD_PRIORITY_TIME_CRITICAL15</term>
	/// <term>
	/// Base priority of 15 for IDLE_PRIORITY_CLASS, BELOW_NORMAL_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, ABOVE_NORMAL_PRIORITY_CLASS, or
	/// HIGH_PRIORITY_CLASS processes, and a base priority of 31 for REALTIME_PRIORITY_CLASS processes.
	/// </term>
	/// </item>
	/// </list>
	/// </para>
	/// <para>
	/// If the thread has the <c>REALTIME_PRIORITY_CLASS</c> base class, this parameter can also be -7, -6, -5, -4, -3, 3, 4, 5, or 6. For
	/// more information, see Scheduling Priorities.
	/// </para>
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
	/// <para>
	/// <c>Windows Phone 8.1:</c> Windows Phone Store apps may call this function but it has no effect. The function will return a nonzero
	/// value indicating success.
	/// </para>
	/// </returns>
	// BOOL WINAPI SetThreadPriority( _In_ HANDLE hThread, _In_ int nPriority); https://msdn.microsoft.com/en-us/library/windows/desktop/ms686277(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms686277")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool SetThreadPriority([In, AddAsMember] HTHREAD hThread, int nPriority);

	/// <summary>Disables or enables the ability of the system to temporarily boost the priority of a thread.</summary>
	/// <param name="hThread">
	/// <para>
	/// A handle to the thread whose priority is to be boosted. The handle must have the <c>THREAD_SET_INFORMATION</c> or
	/// <c>THREAD_SET_LIMITED_INFORMATION</c> access right. For more information, see Thread Security and Access Rights.
	/// </para>
	/// <para><c>Windows Server 2003 and Windows XP:</c> The handle must have the <c>THREAD_SET_INFORMATION</c> access right.</para>
	/// </param>
	/// <param name="DisablePriorityBoost">
	/// If this parameter is <c>TRUE</c>, dynamic boosting is disabled. If the parameter is <c>FALSE</c>, dynamic boosting is enabled.
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// BOOL WINAPI SetThreadPriorityBoost( _In_ HANDLE hThread, _In_ BOOL DisablePriorityBoost); https://msdn.microsoft.com/en-us/library/windows/desktop/ms686280(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms686280")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool SetThreadPriorityBoost([In, AddAsMember] HTHREAD hThread, [MarshalAs(UnmanagedType.Bool)] bool DisablePriorityBoost);

	/// <summary>
	/// Sets the selected CPU Sets assignment for the specified thread. This assignment overrides the process default assignment, if one is set.
	/// </summary>
	/// <param name="Thread">
	/// Specifies the thread on which to set the CPU Set assignment. PROCESS_SET_LIMITED_INFORMATION access right. The value returned by
	/// GetCurrentProcess can also be specified here.
	/// </param>
	/// <param name="CpuSetMasks">
	/// Specifies an optional buffer of GROUP_AFFINITY structures representing the CPU Sets to set as the thread selected CPU set. If this is
	/// NULL, the <c>SetThreadSelectedCpuSetMasks</c> function clears out any assignment, reverting to process default assignment if one is set.
	/// </param>
	/// <param name="CpuSetMaskCount">
	/// Specifies the number of <c>GROUP_AFFINITY</c> structures in the list passed in the GroupCpuSets argument. If the buffer is NULL, this
	/// value must be zero.
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero and extended error information can be retrieved by calling GetLastError.</para>
	/// </returns>
	/// <remarks>
	/// This function is analogous to SetThreadSelectedCpuSets, except that it uses group affinities as opposed to CPU Set IDs to represent a
	/// list of CPU sets. This means that the resulting thread selected CPU Set assignment is the set of all CPU sets with a home processor
	/// in the provided list of group affinities.
	/// </remarks>
	// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreadselectedcpusetmasks BOOL
	// SetThreadSelectedCpuSetMasks( HANDLE Thread, PGROUP_AFFINITY CpuSetMasks, USHORT CpuSetMaskCount );
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("processthreadsapi.h", MSDNShortId = "NF:processthreadsapi.SetThreadSelectedCpuSetMasks")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool SetThreadSelectedCpuSetMasks([In, AddAsMember] HTHREAD Thread,
		[In, Optional, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] GROUP_AFFINITY[]? CpuSetMasks, [Optional] ushort CpuSetMaskCount);

	/// <summary>
	/// Sets the selected CPU Sets assignment for the specified thread. This assignment overrides the process default assignment, if one is set.
	/// </summary>
	/// <param name="Thread">
	/// Specifies the thread on which to set the CPU Set assignment. This handle must have the THREAD_SET_LIMITED_INFORMATION access right.
	/// The value returned by <c>GetCurrentThread</c> can also be used.
	/// </param>
	/// <param name="CpuSetIds">
	/// Specifies the list of CPU Set IDs to set as the thread selected CPU set. If this is NULL, the API clears out any assignment,
	/// reverting to process default assignment if one is set.
	/// </param>
	/// <param name="CpuSetIdCount">
	/// Specifies the number of IDs in the list passed in the <c>CpuSetIds</c> argument. If that value is NULL, this should be 0.
	/// </param>
	/// <returns>This function cannot fail when passed valid parameters.</returns>
	// BOOL WINAPI SetThreadSelectedCpuSets( _In_ HANDLE Thread, _In_ const ULONG *CpuSetIds, _In_ ULONG CpuSetIdCount); https://msdn.microsoft.com/en-us/library/windows/desktop/mt186428(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
	[PInvokeData("Processthreadapi.h", MSDNShortId = "mt186428")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool SetThreadSelectedCpuSets([In, Optional] HTHREAD Thread, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] uint[]? CpuSetIds, [Optional] uint CpuSetIdCount);

	/// <summary>
	/// Sets the minimum size of the stack associated with the calling thread or fiber that will be available during any stack overflow
	/// exceptions. This is useful for handling stack overflow exceptions; the application can safely use the specified number of bytes
	/// during exception handling.
	/// </summary>
	/// <param name="StackSizeInBytes">
	/// <para>The size of the stack, in bytes. On return, this value is set to the size of the previous stack, in bytes.</para>
	/// <para>If this parameter is 0 (zero), the function succeeds and the parameter contains the size of the current stack.</para>
	/// <para>
	/// If the specified size is less than the current size, the function succeeds but ignores this request. Therefore, you cannot use this
	/// function to reduce the size of the stack.
	/// </para>
	/// <para>This value cannot be larger than the reserved stack size.</para>
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is 0 (zero). To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// BOOL WINAPI SetThreadStackGuarantee( _Inout_ PULONG StackSizeInBytes); https://msdn.microsoft.com/en-us/library/windows/desktop/ms686283(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms686283")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool SetThreadStackGuarantee(ref uint StackSizeInBytes);

	/// <summary>
	/// <para>Suspends the specified thread.</para>
	/// <para>A 64-bit application can suspend a WOW64 thread using the <c>Wow64SuspendThread</c> function.</para>
	/// </summary>
	/// <param name="hThread">
	/// <para>A handle to the thread that is to be suspended.</para>
	/// <para>The handle must have the <c>THREAD_SUSPEND_RESUME</c> access right. For more information, see Thread Security and Access Rights.</para>
	/// </param>
	/// <returns>
	/// If the function succeeds, the return value is the thread's previous suspend count; otherwise, it is . To get extended error
	/// information, use the <c>GetLastError</c> function.
	/// </returns>
	// DWORD WINAPI SuspendThread( _In_ HANDLE hThread); https://msdn.microsoft.com/en-us/library/windows/desktop/ms686345(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms686345")]
	public static extern uint SuspendThread([In, AddAsMember] HTHREAD hThread);

	/// <summary>
	/// Causes the calling thread to yield execution to another thread that is ready to run on the current processor. The operating system
	/// selects the next thread to be executed.
	/// </summary>
	/// <returns>
	/// <para>
	/// If calling the <c>SwitchToThread</c> function causes the operating system to switch execution to another thread, the return value is nonzero.
	/// </para>
	/// <para>
	/// If there are no other threads ready to execute, the operating system does not switch execution to another thread, and the return
	/// value is zero.
	/// </para>
	/// </returns>
	// BOOL WINAPI SwitchToThread(void); https://msdn.microsoft.com/en-us/library/windows/desktop/ms686352(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms686352")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool SwitchToThread();

	/// <summary>Terminates the specified process and all of its threads.</summary>
	/// <param name="hProcess">
	/// <para>A handle to the process to be terminated.</para>
	/// <para>The handle must have the <c>PROCESS_TERMINATE</c> access right. For more information, see Process Security and Access Rights.</para>
	/// </param>
	/// <param name="uExitCode">
	/// The exit code to be used by the process and threads terminated as a result of this call. Use the <c>GetExitCodeProcess</c> function
	/// to retrieve a process's exit value. Use the <c>GetExitCodeThread</c> function to retrieve a thread's exit value.
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// BOOL WINAPI TerminateProcess( _In_ HANDLE hProcess, _In_ UINT uExitCode); https://msdn.microsoft.com/en-us/library/windows/desktop/ms686714(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms686714")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool TerminateProcess([In, AddAsMember] HPROCESS hProcess, uint uExitCode);

	/// <summary>Terminates a thread.</summary>
	/// <param name="hThread">
	/// <para>A handle to the thread to be terminated.</para>
	/// <para>The handle must have the <c>THREAD_TERMINATE</c> access right. For more information, see Thread Security and Access Rights.</para>
	/// </param>
	/// <param name="dwExitCode">The exit code for the thread. Use the <c>GetExitCodeThread</c> function to retrieve a thread's exit value.</param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// BOOL WINAPI TerminateThread( _Inout_ HANDLE hThread, _In_ DWORD dwExitCode); https://msdn.microsoft.com/en-us/library/windows/desktop/ms686717(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms686717")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool TerminateThread([In, AddAsMember] HTHREAD hThread, uint dwExitCode);

	/// <summary>
	/// Allocates a thread local storage (TLS) index. Any thread of the process can subsequently use this index to store and retrieve values
	/// that are local to the thread, because each thread receives its own slot for the index.
	/// </summary>
	/// <returns>
	/// <para>If the function succeeds, the return value is a TLS index. The slots for the index are initialized to zero.</para>
	/// <para>If the function fails, the return value is <c>TLS_OUT_OF_INDEXES</c>. To get extended error information, call GetLastError.</para>
	/// </returns>
	/// <remarks>
	/// <para>
	/// <c>Windows Phone 8.1:</c> This function is supported for Windows Phone Store apps on Windows Phone 8.1 and later. When a Windows
	/// Phone Store app calls this function, it is replaced with an inline call to <c>FlsAlloc</c>. Refer to FlsAlloc for function documentation.
	/// </para>
	/// <para>
	/// <c>Windows 8.1</c>, <c>Windows Server 2012 R2</c>, and <c>Windows 10, version 1507</c>: This function is supported for Windows Store
	/// apps on Windows 8.1, Windows Server 2012 R2, and Windows 10, version 1507. When a Windows Store app calls this function, it is
	/// replaced with an inline call to <c>FlsAlloc</c>. Refer to FlsAlloc for function documentation.
	/// </para>
	/// <para>
	/// <c>Windows 10, version 1511</c> and <c>Windows 10, version 1607</c>: This function is fully supported for Universal Windows Platform
	/// (UWP) apps, and is no longer replaced with an inline call to <c>FlsAlloc</c>.
	/// </para>
	/// <para>
	/// The threads of the process can use the TLS index in subsequent calls to the TlsFree, TlsSetValue, or TlsGetValue functions. The value
	/// of the TLS index should be treated as an opaque value; do not assume that it is an index into a zero-based array.
	/// </para>
	/// <para>
	/// TLS indexes are typically allocated during process or dynamic-link library (DLL) initialization. When a TLS index is allocated, its
	/// storage slots are initialized to <c>NULL</c>. After a TLS index has been allocated, each thread of the process can use it to access
	/// its own TLS storage slot. To store a value in its TLS slot, a thread specifies the index in a call to TlsSetValue. The thread
	/// specifies the same index in a subsequent call to TlsGetValue, to retrieve the stored value.
	/// </para>
	/// <para>
	/// TLS indexes are not valid across process boundaries. A DLL cannot assume that an index assigned in one process is valid in another process.
	/// </para>
	/// <para>Examples</para>
	/// <para>For an example, see Using Thread Local Storage or Using Thread Local Storage in a Dynamic-Link Library.</para>
	/// </remarks>
	// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-tlsalloc DWORD TlsAlloc( );
	[DllImport(Lib.KernelBase, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("processthreadsapi.h", MSDNShortId = "cbb3d832-cd92-4875-8366-6b69be7a536f")]
	public static extern uint TlsAlloc();

	/// <summary>Releases a thread local storage (TLS) index, making it available for reuse.</summary>
	/// <param name="dwTlsIndex">The TLS index that was allocated by the TlsAlloc function.</param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call GetLastError.</para>
	/// </returns>
	/// <remarks>
	/// <para>
	/// <c>Windows Phone 8.1:</c> This function is supported for Windows Phone Store apps on Windows Phone 8.1 and later. When a Windows
	/// Phone Store app calls this function, it is replaced with an inline call to <c>FlsFree</c>. Refer to FlsFree for function documentation.
	/// </para>
	/// <para>
	/// <c>Windows 8.1</c>, <c>Windows Server 2012 R2</c>, and <c>Windows 10, version 1507</c>: This function is supported for Windows Store
	/// apps on Windows 8.1, Windows Server 2012 R2, and Windows 10, version 1507. When a Windows Store app calls this function, it is
	/// replaced with an inline call to <c>FlsFree</c>. Refer to FlsFree for function documentation.
	/// </para>
	/// <para>
	/// <c>Windows 10, version 1511</c> and <c>Windows 10, version 1607</c>: This function is fully supported for Universal Windows Platform
	/// (UWP) apps, and is no longer replaced with an inline call to <c>FlsFree</c>.
	/// </para>
	/// <para>
	/// If the threads of the process have allocated memory and stored a pointer to the memory in a TLS slot, they should free the memory
	/// before calling <c>TlsFree</c>. The <c>TlsFree</c> function does not free memory blocks whose addresses have been stored in the TLS
	/// slots associated with the TLS index. It is expected that DLLs call this function (if at all) only during <c>DLL_PROCESS_DETACH</c>.
	/// </para>
	/// <para>For more information, see Thread Local Storage.</para>
	/// <para>Examples</para>
	/// <para>For an example, see Using Thread Local Storage or Using Thread Local Storage in a Dynamic-Link Library.</para>
	/// </remarks>
	// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-tlsfree BOOL TlsFree( DWORD dwTlsIndex );
	[DllImport(Lib.KernelBase, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("processthreadsapi.h", MSDNShortId = "f5b1e8fc-02eb-4a06-b606-2b647944029b")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool TlsFree(uint dwTlsIndex);

	/// <summary>
	/// Retrieves the value in the calling thread's thread local storage (TLS) slot for the specified TLS index. Each thread of a process has
	/// its own slot for each TLS index.
	/// </summary>
	/// <param name="dwTlsIndex">The TLS index that was allocated by the TlsAlloc function.</param>
	/// <returns>
	/// <para>
	/// If the function succeeds, the return value is the value stored in the calling thread's TLS slot associated with the specified index.
	/// If dwTlsIndex is a valid index allocated by a successful call to TlsAlloc, this function always succeeds.
	/// </para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call GetLastError.</para>
	/// <para>
	/// The data stored in a TLS slot can have a value of 0 because it still has its initial value or because the thread called the
	/// TlsSetValue function with 0. Therefore, if the return value is 0, you must check whether GetLastError returns <c>ERROR_SUCCESS</c>
	/// before determining that the function has failed. If <c>GetLastError</c> returns <c>ERROR_SUCCESS</c>, then the function has succeeded
	/// and the data stored in the TLS slot is 0. Otherwise, the function has failed.
	/// </para>
	/// <para>
	/// Functions that return indications of failure call SetLastErrorwhen they fail. They generally do not call <c>SetLastError</c> when
	/// they succeed. The <c>TlsGetValue</c> function is an exception to this general rule. The <c>TlsGetValue</c> function calls
	/// <c>SetLastError</c> to clear a thread's last error when it succeeds. That allows checking for the error-free retrieval of zero values.
	/// </para>
	/// </returns>
	/// <remarks>
	/// <para>
	/// <c>Windows Phone 8.1:</c> This function is supported for Windows Phone Store apps on Windows Phone 8.1 and later. When a Windows
	/// Phone Store app calls this function, it is replaced with an inline call to <c>FlsGetValue</c>. Refer to FlsGetValue for function documentation.
	/// </para>
	/// <para>
	/// <c>Windows 8.1</c>, <c>Windows Server 2012 R2</c>, and <c>Windows 10, version 1507</c>: This function is supported for Windows Store
	/// apps on Windows 8.1, Windows Server 2012 R2, and Windows 10, version 1507. When a Windows Store app calls this function, it is
	/// replaced with an inline call to <c>FlsGetValue</c>. Refer to FlsGetValue for function documentation.
	/// </para>
	/// <para>
	/// <c>Windows 10, version 1511</c> and <c>Windows 10, version 1607</c>: This function is fully supported for Universal Windows Platform
	/// (UWP) apps, and is no longer replaced with an inline call to <c>FlsGetValue</c>.
	/// </para>
	/// <para>
	/// TLS indexes are typically allocated by the TlsAlloc function during process or DLL initialization. After a TLS index is allocated,
	/// each thread of the process can use it to access its own TLS slot for that index. A thread specifies a TLS index in a call to
	/// TlsSetValue to store a value in its slot. The thread specifies the same index in a subsequent call to <c>TlsGetValue</c> to retrieve
	/// the stored value.
	/// </para>
	/// <para>
	/// <c>TlsGetValue</c> was implemented with speed as the primary goal. The function performs minimal parameter validation and error
	/// checking. In particular, it succeeds if dwTlsIndex is in the range 0 through ( <c>TLS_MINIMUM_AVAILABLE</c>– 1). It is up to the
	/// programmer to ensure that the index is valid and that the thread calls TlsSetValue before calling <c>TlsGetValue</c>.
	/// </para>
	/// <para>Examples</para>
	/// <para>For an example, see Using Thread Local Storage or Using Thread Local Storage in a Dynamic-Link Library.</para>
	/// </remarks>
	// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-tlsgetvalue LPVOID TlsGetValue( DWORD
	// dwTlsIndex );
	[DllImport(Lib.KernelBase, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("processthreadsapi.h", MSDNShortId = "82bd5ff6-ff0b-42b7-9ece-e9e8531eb5fb")]
	public static extern IntPtr TlsGetValue(uint dwTlsIndex);

	/// <summary>
	/// <para>Important</para>
	/// <para>
	/// Some information relates to a prerelease product which may be substantially modified before it's commercially released. Microsoft
	/// makes no warranties, express or implied, with respect to the information provided here.
	/// </para>
	/// </summary>
	/// <param name="dwTlsIndex">The TLS index that was allocated by the TlsAlloc function.</param>
	/// <returns>
	/// <para>
	/// If the function succeeds, the return value is the value stored in the calling thread's TLS slot associated with the specified index.
	/// If dwTlsIndex is a valid index allocated by a successful call to TlsAlloc, this function always succeeds.
	/// </para>
	/// <para>If the function fails, the return value is zero.</para>
	/// </returns>
	/// <remarks>
	/// <para>
	/// TLS indexes are typically allocated by the TlsAlloc function during process or DLL initialization. After a TLS index is allocated,
	/// each thread of the process can use it to access its own TLS slot for that index. A thread specifies a TLS index in a call to
	/// TlsSetValue to store a value in its slot. The thread specifies the same index in a subsequent call to <c>TlsGetValue2</c> to
	/// retrieve the stored value.
	/// </para>
	/// <para>
	/// <c>TlsGetValue2</c> was implemented with speed as the primary goal. The function performs minimal parameter validation and error
	/// checking. In particular, it succeeds if dwTlsIndex is in the range 0 through ( <c>TLS_MINIMUM_AVAILABLE</c>– 1). It is up to the
	/// programmer to ensure that the index is valid and that the thread calls TlsSetValue before calling <c>TlsGetValue2</c>.
	/// </para>
	/// <para>
	/// This function is identical to <c>TlsGetValue</c> except that it doesn't set the thread's last error. Applications calling this
	/// function should avoid using 0 as a valid value, because <c>GetLastError</c> cannot be called to check if the function failed.
	/// </para>
	/// <para>Examples</para>
	/// <para>See Using Thread Local Storage or Using Thread Local Storage in a Dynamic-Link Library.</para>
	/// </remarks>
	// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-tlsgetvalue2
	// LPVOID TlsGetValue2( [in] DWORD dwTlsIndex );
	[PInvokeData("processthreadsapi.h", MSDNShortId = "NF:processthreadsapi.TlsGetValue2")]
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	public static extern IntPtr TlsGetValue2(uint dwTlsIndex);

	/// <summary>
	/// Stores a value in the calling thread's thread local storage (TLS) slot for the specified TLS index. Each thread of a process has its
	/// own slot for each TLS index.
	/// </summary>
	/// <param name="dwTlsIndex">The TLS index that was allocated by the TlsAlloc function.</param>
	/// <param name="lpTlsValue">The value to be stored in the calling thread's TLS slot for the index.</param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call GetLastError.</para>
	/// </returns>
	/// <remarks>
	/// <para>
	/// <c>Windows Phone 8.1:</c> This function is supported for Windows Phone Store apps on Windows Phone 8.1 and later. When a Windows
	/// Phone Store app calls this function, it is replaced with an inline call to <c>FlsSetValue</c>. Refer to FlsSetValue for function documentation.
	/// </para>
	/// <para>
	/// <c>Windows 8.1</c>, <c>Windows Server 2012 R2</c>, and <c>Windows 10, version 1507</c>: This function is supported for Windows Store
	/// apps on Windows 8.1, Windows Server 2012 R2, and Windows 10, version 1507. When a Windows Store app calls this function, it is
	/// replaced with an inline call to <c>FlsSetValue</c>. Refer to FlsSetValue for function documentation.
	/// </para>
	/// <para>
	/// <c>Windows 10, version 1511</c> and <c>Windows 10, version 1607</c>: This function is fully supported for Universal Windows Platform
	/// (UWP) apps, and is no longer replaced with an inline call to <c>FlsSetValue</c>.
	/// </para>
	/// <para>
	/// TLS indexes are typically allocated by the TlsAlloc function during process or DLL initialization. When a TLS index is allocated, its
	/// storage slots are initialized to NULL. After a TLS index is allocated, each thread of the process can use it to access its own TLS
	/// slot for that index. A thread specifies a TLS index in a call to <c>TlsSetValue</c>, to store a value in its slot. The thread
	/// specifies the same index in a subsequent call to TlsGetValue, to retrieve the stored value.
	/// </para>
	/// <para>
	/// <c>TlsSetValue</c> was implemented with speed as the primary goal. The function performs minimal parameter validation and error
	/// checking. In particular, it succeeds if dwTlsIndex is in the range 0 through ( <c>TLS_MINIMUM_AVAILABLE</c>– 1). It is up to the
	/// programmer to ensure that the index is valid before calling TlsGetValue.
	/// </para>
	/// <para>Examples</para>
	/// <para>For an example, see Using Thread Local Storage or Using Thread Local Storage in a Dynamic-Link Library.</para>
	/// </remarks>
	// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-tlssetvalue BOOL TlsSetValue( DWORD
	// dwTlsIndex, LPVOID lpTlsValue );
	[DllImport(Lib.KernelBase, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("processthreadsapi.h", MSDNShortId = "531b4a4a-a251-4ab4-b00a-754783a51283")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool TlsSetValue(uint dwTlsIndex, [In] IntPtr lpTlsValue);

	/// <summary>Updates the specified attribute in a list of attributes for process and thread creation.</summary>
	/// <param name="lpAttributeList">A pointer to an attribute list created by the <c>InitializeProcThreadAttributeList</c> function.</param>
	/// <param name="dwFlags">This parameter is reserved and must be zero.</param>
	/// <param name="Attribute">
	/// <para>The attribute key to update in the attribute list. This parameter can be one of the following values.</para>
	/// <para>
	/// <list type="table">
	/// <listheader>
	/// <term>Value</term>
	/// <term>Meaning</term>
	/// </listheader>
	/// <item>
	/// <term>PROC_THREAD_ATTRIBUTE_GROUP_AFFINITY</term>
	/// <term>
	/// The lpValue parameter is a pointer to a GROUP_AFFINITY structure that specifies the processor group affinity for the new
	/// thread.Windows Server 2008 and Windows Vista: This value is not supported until Windows 7 and Windows Server 2008 R2.
	/// </term>
	/// </item>
	/// <item>
	/// <term>PROC_THREAD_ATTRIBUTE_HANDLE_LIST</term>
	/// <term>
	/// The lpValue parameter is a pointer to a list of handles to be inherited by the child process.These handles must be created as
	/// inheritable handles and must not include pseudo handles such as those returned by the GetCurrentProcess or GetCurrentThread function.
	/// </term>
	/// </item>
	/// <item>
	/// <term>PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR</term>
	/// <term>
	/// The lpValue parameter is a pointer to a PROCESSOR_NUMBER structure that specifies the ideal processor for the new thread.Windows
	/// Server 2008 and Windows Vista: This value is not supported until Windows 7 and Windows Server 2008 R2.
	/// </term>
	/// </item>
	/// <item>
	/// <term>PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY</term>
	/// <term>
	/// The lpValue parameter is a pointer to a DWORD or DWORD64 that specifies the exploit mitigation policy for the child process. Starting
	/// in Windows 10, version 1703, this parameter can also be a pointer to a two-element DWORD64 array.The specified policy overrides the
	/// policies set for the application and the system and cannot be changed after the child process starts running. Windows Server 2008 and
	/// Windows Vista: This value is not supported until Windows 7 and Windows Server 2008 R2.The DWORD or DWORD64 pointed to by lpValue can
	/// be one or more of the values listed in the remarks.
	/// </term>
	/// </item>
	/// <item>
	/// <term>PROC_THREAD_ATTRIBUTE_PARENT_PROCESS</term>
	/// <term>
	/// The lpValue parameter is a pointer to a handle to a process to use instead of the calling process as the parent for the process being
	/// created. The process to use must have the PROCESS_CREATE_PROCESS access right.Attributes inherited from the specified process include
	/// handles, the device map, processor affinity, priority, quotas, the process token, and job object. (Note that some attributes such as
	/// the debug port will come from the creating process, not the process specified by this handle.)
	/// </term>
	/// </item>
	/// <item>
	/// <term>PROC_THREAD_ATTRIBUTE_PREFERRED_NODE</term>
	/// <term>
	/// The lpValue parameter is a pointer to the node number of the preferred NUMA node for the new process.Windows Server 2008 and Windows
	/// Vista: This value is not supported until Windows 7 and Windows Server 2008 R2.
	/// </term>
	/// </item>
	/// <item>
	/// <term>PROC_THREAD_ATTRIBUTE_UMS_THREAD</term>
	/// <term>
	/// The lpValue parameter is a pointer to a UMS_CREATE_THREAD_ATTRIBUTES structure that specifies a user-mode scheduling (UMS) thread
	/// context and a UMS completion list to associate with the thread. After the UMS thread is created, the system queues it to the
	/// specified completion list. The UMS thread runs only when an application's UMS scheduler retrieves the UMS thread from the completion
	/// list and selects it to run. For more information, see User-Mode Scheduling.Windows Server 2008 and Windows Vista: This value is not
	/// supported until Windows 7 and Windows Server 2008 R2.
	/// </term>
	/// </item>
	/// <item>
	/// <term>PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES</term>
	/// <term>
	/// The lpValue parameter is a pointer to a SECURITY_CAPABILITIES structure that defines the security capabilities of an app container.
	/// If this attribute is set the new process will be created as an AppContainer process.Windows 7, Windows Server 2008 R2, Windows Server
	/// 2008 and Windows Vista: This value is not supported until Windows 8 and Windows Server 2012.
	/// </term>
	/// </item>
	/// <item>
	/// <term>PROC_THREAD_ATTRIBUTE_PROTECTION_LEVEL</term>
	/// <term>
	/// The lpValue parameter is a pointer to a DWORD value of PROTECTION_LEVEL_SAME. This specifies the protection level of the child
	/// process to be the same as the protection level of its parent process.
	/// </term>
	/// </item>
	/// <item>
	/// <term>PROC_THREAD_ATTRIBUTE_CHILD_PROCESS_POLICY</term>
	/// <term>
	/// The lpValue parameter is a pointer to a DWORD or DWORD64 value that specifies the child process policy. THe policy specifies whether
	/// to allow a child process to be created.For information on the possible values for the DWORD or DWORD64 to which lpValue points, see Remarks.
	/// </term>
	/// </item>
	/// <item>
	/// <term>PROC_THREAD_ATTRIBUTE_DESKTOP_APP_POLICY</term>
	/// <term>
	/// This attribute is relevant only to win32 applications that have been converted to UWP packages by using the Desktop Bridge. The
	/// lpValue parameter is a pointer to a DWORD value that specifies the desktop app policy. The policy specifies whether descendant
	/// processes should continue to run in the desktop environment.For information about the possible values for the DWORD to which lpValue
	/// points, see Remarks.
	/// </term>
	/// </item>
	/// </list>
	/// </para>
	/// </param>
	/// <param name="lpValue">
	/// A pointer to the attribute value. This value should persist until the attribute is destroyed using the
	/// <c>DeleteProcThreadAttributeList</c> function.
	/// </param>
	/// <param name="cbSize">The size of the attribute value specified by the lpValue parameter.</param>
	/// <param name="lpPreviousValue">This parameter is reserved and must be NULL.</param>
	/// <param name="lpReturnSize">This parameter is reserved and must be NULL.</param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
	/// </returns>
	// BOOL WINAPI UpdateProcThreadAttribute( _Inout_ LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList, _In_ DWORD dwFlags, _In_ DWORD_PTR
	// Attribute, _In_ PVOID lpValue, _In_ SIZE_T cbSize, _Out_opt_ PVOID lpPreviousValue, _In_opt_ PSIZE_T lpReturnSize); https://msdn.microsoft.com/en-us/library/windows/desktop/ms686880(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms686880")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool UpdateProcThreadAttribute(IntPtr lpAttributeList, [Optional] uint dwFlags, PROC_THREAD_ATTRIBUTE Attribute, IntPtr lpValue,
		SizeT cbSize, [Optional] IntPtr lpPreviousValue, [Optional] IntPtr lpReturnSize);

	/// <summary>
	/// <para>Creates a new process and its primary thread. The new process runs in the security context of the calling process.</para>
	/// <para>
	/// If the calling process is impersonating another user, the new process uses the token for the calling process, not the impersonation
	/// token. To run the new process in the security context of the user represented by the impersonation token, use the
	/// <c>CreateProcessAsUser</c> or <c>CreateProcessWithLogonW</c> function.
	/// </para>
	/// </summary>
	/// <param name="lpApplicationName">
	/// <para>
	/// The name of the module to be executed. This module can be a Windows-based application. It can be some other type of module (for
	/// example, MS-DOS or OS/2) if the appropriate subsystem is available on the local computer.
	/// </para>
	/// <para>
	/// The string can specify the full path and file name of the module to execute or it can specify a partial name. In the case of a
	/// partial name, the function uses the current drive and current directory to complete the specification. The function will not use the
	/// search path. This parameter must include the file name extension; no default extension is assumed.
	/// </para>
	/// <para>
	/// The lpApplicationName parameter can be <c>NULL</c>. In that case, the module name must be the first white space–delimited token in
	/// the lpCommandLine string. If you are using a long file name that contains a space, use quoted strings to indicate where the file name
	/// ends and the arguments begin; otherwise, the file name is ambiguous. For example, consider the string "c:\program files\sub
	/// dir\program name". This string can be interpreted in a number of ways. The system tries to interpret the possibilities in the
	/// following order:
	/// </para>
	/// <para>
	/// If the executable module is a 16-bit application, lpApplicationName should be <c>NULL</c>, and the string pointed to by lpCommandLine
	/// should specify the executable module as well as its arguments.
	/// </para>
	/// <para>
	/// To run a batch file, you must start the command interpreter; set lpApplicationName to cmd.exe and set lpCommandLine to the following
	/// arguments: /c plus the name of the batch file.
	/// </para>
	/// </param>
	/// <param name="lpCommandLine">
	/// <para>
	/// The command line to be executed. The maximum length of this string is 32,768 characters, including the Unicode terminating null
	/// character. If lpApplicationName is <c>NULL</c>, the module name portion of lpCommandLine is limited to <c>MAX_PATH</c> characters.
	/// </para>
	/// <para>
	/// The Unicode version of this function, <c>CreateProcessW</c>, can modify the contents of this string. Therefore, this parameter cannot
	/// be a pointer to read-only memory (such as a <c>const</c> variable or a literal string). If this parameter is a constant string, the
	/// function may cause an access violation.
	/// </para>
	/// <para>
	/// The lpCommandLine parameter can be NULL. In that case, the function uses the string pointed to by lpApplicationName as the command line.
	/// </para>
	/// <para>
	/// If both lpApplicationName and lpCommandLine are non- <c>NULL</c>, the null-terminated string pointed to by lpApplicationName
	/// specifies the module to execute, and the null-terminated string pointed to by lpCommandLine specifies the command line. The new
	/// process can use <c>GetCommandLine</c> to retrieve the entire command line. Console processes written in C can use the argc and argv
	/// arguments to parse the command line. Because argv[0] is the module name, C programmers generally repeat the module name as the first
	/// token in the command line.
	/// </para>
	/// <para>
	/// If lpApplicationName is NULL, the first white space–delimited token of the command line specifies the module name. If you are using a
	/// long file name that contains a space, use quoted strings to indicate where the file name ends and the arguments begin (see the
	/// explanation for the lpApplicationName parameter). If the file name does not contain an extension, .exe is appended. Therefore, if the
	/// file name extension is .com, this parameter must include the .com extension. If the file name ends in a period (.) with no extension,
	/// or if the file name contains a path, .exe is not appended. If the file name does not contain a directory path, the system searches
	/// for the executable file in the following sequence:
	/// </para>
	/// <para>
	/// The system adds a terminating null character to the command-line string to separate the file name from the arguments. This divides
	/// the original string into two strings for internal processing.
	/// </para>
	/// </param>
	/// <param name="lpProcessAttributes">
	/// <para>
	/// A pointer to a <c>SECURITY_ATTRIBUTES</c> structure that determines whether the returned handle to the new process object can be
	/// inherited by child processes. If lpProcessAttributes is <c>NULL</c>, the handle cannot be inherited.
	/// </para>
	/// <para>
	/// The <c>lpSecurityDescriptor</c> member of the structure specifies a security descriptor for the new process. If lpProcessAttributes
	/// is NULL or <c>lpSecurityDescriptor</c> is <c>NULL</c>, the process gets a default security descriptor. The ACLs in the default
	/// security descriptor for a process come from the primary token of the creator.
	/// </para>
	/// <para>
	/// <c>Windows XP:</c> The ACLs in the default security descriptor for a process come from the primary or impersonation token of the
	/// creator. This behavior changed with Windows XP with SP2 and Windows Server 2003.
	/// </para>
	/// </param>
	/// <param name="lpThreadAttributes">
	/// <para>
	/// A pointer to a <c>SECURITY_ATTRIBUTES</c> structure that determines whether the returned handle to the new thread object can be
	/// inherited by child processes. If lpThreadAttributes is NULL, the handle cannot be inherited.
	/// </para>
	/// <para>
	/// The <c>lpSecurityDescriptor</c> member of the structure specifies a security descriptor for the main thread. If lpThreadAttributes is
	/// NULL or <c>lpSecurityDescriptor</c> is NULL, the thread gets a default security descriptor. The ACLs in the default security
	/// descriptor for a thread come from the process token.
	/// </para>
	/// <para>
	/// <c>Windows XP:</c> The ACLs in the default security descriptor for a thread come from the primary or impersonation token of the
	/// creator. This behavior changed with Windows XP with SP2 and Windows Server 2003.
	/// </para>
	/// </param>
	/// <param name="bInheritHandles">
	/// <para>
	/// If this parameter is TRUE, each inheritable handle in the calling process is inherited by the new process. If the parameter is FALSE,
	/// the handles are not inherited. Note that inherited handles have the same value and access rights as the original handles.
	/// </para>
	/// <para>
	/// <c>Terminal Services:</c> You cannot inherit handles across sessions. Additionally, if this parameter is TRUE, you must create the
	/// process in the same session as the caller.
	/// </para>
	/// <para>
	/// <c>Protected Process Light (PPL) processes:</c> The generic handle inheritance is blocked when a PPL process creates a non-PPL
	/// process since PROCESS_DUP_HANDLE is not allowed from a non-PPL process to a PPL process. See Process Security and Access Rights
	/// </para>
	/// </param>
	/// <param name="dwCreationFlags">
	/// <para>The flags that control the priority class and the creation of the process. For a list of values, see Process Creation Flags.</para>
	/// <para>
	/// This parameter also controls the new process's priority class, which is used to determine the scheduling priorities of the process's
	/// threads. For a list of values, see <c>GetPriorityClass</c>. If none of the priority class flags is specified, the priority class
	/// defaults to <c>NORMAL_PRIORITY_CLASS</c> unless the priority class of the creating process is <c>IDLE_PRIORITY_CLASS</c> or
	/// <c>BELOW_NORMAL_PRIORITY_CLASS</c>. In this case, the child process receives the default priority class of the calling process.
	/// </para>
	/// </param>
	/// <param name="lpEnvironment">
	/// <para>
	/// A pointer to the environment block for the new process. If this parameter is <c>NULL</c>, the new process uses the environment of the
	/// calling process.
	/// </para>
	/// <para>An environment block consists of a null-terminated block of null-terminated strings. Each string is in the following form:</para>
	/// <para>name=value\0</para>
	/// <para>Because the equal sign is used as a separator, it must not be used in the name of an environment variable.</para>
	/// <para>
	/// An environment block can contain either Unicode or ANSI characters. If the environment block pointed to by lpEnvironment contains
	/// Unicode characters, be sure that dwCreationFlags includes <c>CREATE_UNICODE_ENVIRONMENT</c>. If this parameter is <c>NULL</c> and the
	/// environment block of the parent process contains Unicode characters, you must also ensure that dwCreationFlags includes <c>CREATE_UNICODE_ENVIRONMENT</c>.
	/// </para>
	/// <para>
	/// The ANSI version of this function, <c>CreateProcessA</c> fails if the total size of the environment block for the process exceeds
	/// 32,767 characters.
	/// </para>
	/// <para>
	/// Note that an ANSI environment block is terminated by two zero bytes: one for the last string, one more to terminate the block. A
	/// Unicode environment block is terminated by four zero bytes: two for the last string, two more to terminate the block.
	/// </para>
	/// </param>
	/// <param name="lpCurrentDirectory">
	/// <para>The full path to the current directory for the process. The string can also specify a UNC path.</para>
	/// <para>
	/// If this parameter is <c>NULL</c>, the new process will have the same current drive and directory as the calling process. (This
	/// feature is provided primarily for shells that need to start an application and specify its initial drive and working directory.)
	/// </para>
	/// </param>
	/// <param name="lpStartupInfo">
	/// <para>A pointer to a <c>STARTUPINFO</c> or <c>STARTUPINFOEX</c> structure.</para>
	/// <para>
	/// To set extended attributes, use a <c>STARTUPINFOEX</c> structure and specify EXTENDED_STARTUPINFO_PRESENT in the dwCreationFlags parameter.
	/// </para>
	/// <para>Handles in <c>STARTUPINFO</c> or <c>STARTUPINFOEX</c> must be closed with <c>CloseHandle</c> when they are no longer needed.</para>
	/// </param>
	/// <param name="lpProcessInformation">
	/// <para>A pointer to a <c>PROCESS_INFORMATION</c> structure that receives identification information about the new process.</para>
	/// <para>Handles in <c>PROCESS_INFORMATION</c> must be closed with <c>CloseHandle</c> when they are no longer needed.</para>
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
	/// <para>
	/// Note that the function returns before the process has finished initialization. If a required DLL cannot be located or fails to
	/// initialize, the process is terminated. To get the termination status of a process, call <c>GetExitCodeProcess</c>.
	/// </para>
	/// </returns>
	// BOOL WINAPI CreateProcess( _In_opt_ LPCTSTR lpApplicationName, _Inout_opt_ LPTSTR lpCommandLine, _In_opt_ LPSECURITY_ATTRIBUTES
	// lpProcessAttributes, _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, _In_ BOOL bInheritHandles, _In_ DWORD dwCreationFlags,
	// _In_opt_ LPVOID lpEnvironment, _In_opt_ LPCTSTR lpCurrentDirectory, _In_ LPSTARTUPINFO lpStartupInfo, _Out_ LPPROCESS_INFORMATION
	// lpProcessInformation); https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, CharSet = CharSet.Auto)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms682425")]
	[return: MarshalAs(UnmanagedType.Bool)]
	private static extern bool CreateProcess([Optional] string? lpApplicationName, [Optional] StringBuilder? lpCommandLine, [In, Optional] SECURITY_ATTRIBUTES? lpProcessAttributes,
		[In, Optional] SECURITY_ATTRIBUTES? lpThreadAttributes, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandles, CREATE_PROCESS dwCreationFlags,
		[In, Optional, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(NullTermStringArrayMarshaler), MarshalCookie = "Auto")] string[]? lpEnvironment,
		[Optional] string? lpCurrentDirectory, in STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);

	/// <summary>
	/// <para>Creates a new process and its primary thread. The new process runs in the security context of the calling process.</para>
	/// <para>
	/// If the calling process is impersonating another user, the new process uses the token for the calling process, not the impersonation
	/// token. To run the new process in the security context of the user represented by the impersonation token, use the
	/// <c>CreateProcessAsUser</c> or <c>CreateProcessWithLogonW</c> function.
	/// </para>
	/// </summary>
	/// <param name="lpApplicationName">
	/// <para>
	/// The name of the module to be executed. This module can be a Windows-based application. It can be some other type of module (for
	/// example, MS-DOS or OS/2) if the appropriate subsystem is available on the local computer.
	/// </para>
	/// <para>
	/// The string can specify the full path and file name of the module to execute or it can specify a partial name. In the case of a
	/// partial name, the function uses the current drive and current directory to complete the specification. The function will not use the
	/// search path. This parameter must include the file name extension; no default extension is assumed.
	/// </para>
	/// <para>
	/// The lpApplicationName parameter can be <c>NULL</c>. In that case, the module name must be the first white space–delimited token in
	/// the lpCommandLine string. If you are using a long file name that contains a space, use quoted strings to indicate where the file name
	/// ends and the arguments begin; otherwise, the file name is ambiguous. For example, consider the string "c:\program files\sub
	/// dir\program name". This string can be interpreted in a number of ways. The system tries to interpret the possibilities in the
	/// following order:
	/// </para>
	/// <para>
	/// If the executable module is a 16-bit application, lpApplicationName should be <c>NULL</c>, and the string pointed to by lpCommandLine
	/// should specify the executable module as well as its arguments.
	/// </para>
	/// <para>
	/// To run a batch file, you must start the command interpreter; set lpApplicationName to cmd.exe and set lpCommandLine to the following
	/// arguments: /c plus the name of the batch file.
	/// </para>
	/// </param>
	/// <param name="lpCommandLine">
	/// <para>
	/// The command line to be executed. The maximum length of this string is 32,768 characters, including the Unicode terminating null
	/// character. If lpApplicationName is <c>NULL</c>, the module name portion of lpCommandLine is limited to <c>MAX_PATH</c> characters.
	/// </para>
	/// <para>
	/// The Unicode version of this function, <c>CreateProcessW</c>, can modify the contents of this string. Therefore, this parameter cannot
	/// be a pointer to read-only memory (such as a <c>const</c> variable or a literal string). If this parameter is a constant string, the
	/// function may cause an access violation.
	/// </para>
	/// <para>
	/// The lpCommandLine parameter can be NULL. In that case, the function uses the string pointed to by lpApplicationName as the command line.
	/// </para>
	/// <para>
	/// If both lpApplicationName and lpCommandLine are non- <c>NULL</c>, the null-terminated string pointed to by lpApplicationName
	/// specifies the module to execute, and the null-terminated string pointed to by lpCommandLine specifies the command line. The new
	/// process can use <c>GetCommandLine</c> to retrieve the entire command line. Console processes written in C can use the argc and argv
	/// arguments to parse the command line. Because argv[0] is the module name, C programmers generally repeat the module name as the first
	/// token in the command line.
	/// </para>
	/// <para>
	/// If lpApplicationName is NULL, the first white space–delimited token of the command line specifies the module name. If you are using a
	/// long file name that contains a space, use quoted strings to indicate where the file name ends and the arguments begin (see the
	/// explanation for the lpApplicationName parameter). If the file name does not contain an extension, .exe is appended. Therefore, if the
	/// file name extension is .com, this parameter must include the .com extension. If the file name ends in a period (.) with no extension,
	/// or if the file name contains a path, .exe is not appended. If the file name does not contain a directory path, the system searches
	/// for the executable file in the following sequence:
	/// </para>
	/// <para>
	/// The system adds a terminating null character to the command-line string to separate the file name from the arguments. This divides
	/// the original string into two strings for internal processing.
	/// </para>
	/// </param>
	/// <param name="lpProcessAttributes">
	/// <para>
	/// A pointer to a <c>SECURITY_ATTRIBUTES</c> structure that determines whether the returned handle to the new process object can be
	/// inherited by child processes. If lpProcessAttributes is <c>NULL</c>, the handle cannot be inherited.
	/// </para>
	/// <para>
	/// The <c>lpSecurityDescriptor</c> member of the structure specifies a security descriptor for the new process. If lpProcessAttributes
	/// is NULL or <c>lpSecurityDescriptor</c> is <c>NULL</c>, the process gets a default security descriptor. The ACLs in the default
	/// security descriptor for a process come from the primary token of the creator.
	/// </para>
	/// <para>
	/// <c>Windows XP:</c> The ACLs in the default security descriptor for a process come from the primary or impersonation token of the
	/// creator. This behavior changed with Windows XP with SP2 and Windows Server 2003.
	/// </para>
	/// </param>
	/// <param name="lpThreadAttributes">
	/// <para>
	/// A pointer to a <c>SECURITY_ATTRIBUTES</c> structure that determines whether the returned handle to the new thread object can be
	/// inherited by child processes. If lpThreadAttributes is NULL, the handle cannot be inherited.
	/// </para>
	/// <para>
	/// The <c>lpSecurityDescriptor</c> member of the structure specifies a security descriptor for the main thread. If lpThreadAttributes is
	/// NULL or <c>lpSecurityDescriptor</c> is NULL, the thread gets a default security descriptor. The ACLs in the default security
	/// descriptor for a thread come from the process token.
	/// </para>
	/// <para>
	/// <c>Windows XP:</c> The ACLs in the default security descriptor for a thread come from the primary or impersonation token of the
	/// creator. This behavior changed with Windows XP with SP2 and Windows Server 2003.
	/// </para>
	/// </param>
	/// <param name="bInheritHandles">
	/// <para>
	/// If this parameter is TRUE, each inheritable handle in the calling process is inherited by the new process. If the parameter is FALSE,
	/// the handles are not inherited. Note that inherited handles have the same value and access rights as the original handles.
	/// </para>
	/// <para>
	/// <c>Terminal Services:</c> You cannot inherit handles across sessions. Additionally, if this parameter is TRUE, you must create the
	/// process in the same session as the caller.
	/// </para>
	/// <para>
	/// <c>Protected Process Light (PPL) processes:</c> The generic handle inheritance is blocked when a PPL process creates a non-PPL
	/// process since PROCESS_DUP_HANDLE is not allowed from a non-PPL process to a PPL process. See Process Security and Access Rights
	/// </para>
	/// </param>
	/// <param name="dwCreationFlags">
	/// <para>The flags that control the priority class and the creation of the process. For a list of values, see Process Creation Flags.</para>
	/// <para>
	/// This parameter also controls the new process's priority class, which is used to determine the scheduling priorities of the process's
	/// threads. For a list of values, see <c>GetPriorityClass</c>. If none of the priority class flags is specified, the priority class
	/// defaults to <c>NORMAL_PRIORITY_CLASS</c> unless the priority class of the creating process is <c>IDLE_PRIORITY_CLASS</c> or
	/// <c>BELOW_NORMAL_PRIORITY_CLASS</c>. In this case, the child process receives the default priority class of the calling process.
	/// </para>
	/// </param>
	/// <param name="lpEnvironment">
	/// <para>
	/// A pointer to the environment block for the new process. If this parameter is <c>NULL</c>, the new process uses the environment of the
	/// calling process.
	/// </para>
	/// <para>An environment block consists of a null-terminated block of null-terminated strings. Each string is in the following form:</para>
	/// <para>name=value\0</para>
	/// <para>Because the equal sign is used as a separator, it must not be used in the name of an environment variable.</para>
	/// <para>
	/// An environment block can contain either Unicode or ANSI characters. If the environment block pointed to by lpEnvironment contains
	/// Unicode characters, be sure that dwCreationFlags includes <c>CREATE_UNICODE_ENVIRONMENT</c>. If this parameter is <c>NULL</c> and the
	/// environment block of the parent process contains Unicode characters, you must also ensure that dwCreationFlags includes <c>CREATE_UNICODE_ENVIRONMENT</c>.
	/// </para>
	/// <para>
	/// The ANSI version of this function, <c>CreateProcessA</c> fails if the total size of the environment block for the process exceeds
	/// 32,767 characters.
	/// </para>
	/// <para>
	/// Note that an ANSI environment block is terminated by two zero bytes: one for the last string, one more to terminate the block. A
	/// Unicode environment block is terminated by four zero bytes: two for the last string, two more to terminate the block.
	/// </para>
	/// </param>
	/// <param name="lpCurrentDirectory">
	/// <para>The full path to the current directory for the process. The string can also specify a UNC path.</para>
	/// <para>
	/// If this parameter is <c>NULL</c>, the new process will have the same current drive and directory as the calling process. (This
	/// feature is provided primarily for shells that need to start an application and specify its initial drive and working directory.)
	/// </para>
	/// </param>
	/// <param name="lpStartupInfo">
	/// <para>A pointer to a <c>STARTUPINFO</c> or <c>STARTUPINFOEX</c> structure.</para>
	/// <para>
	/// To set extended attributes, use a <c>STARTUPINFOEX</c> structure and specify EXTENDED_STARTUPINFO_PRESENT in the dwCreationFlags parameter.
	/// </para>
	/// <para>Handles in <c>STARTUPINFO</c> or <c>STARTUPINFOEX</c> must be closed with <c>CloseHandle</c> when they are no longer needed.</para>
	/// </param>
	/// <param name="lpProcessInformation">
	/// <para>A pointer to a <c>PROCESS_INFORMATION</c> structure that receives identification information about the new process.</para>
	/// <para>Handles in <c>PROCESS_INFORMATION</c> must be closed with <c>CloseHandle</c> when they are no longer needed.</para>
	/// </param>
	/// <returns>
	/// <para>If the function succeeds, the return value is nonzero.</para>
	/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
	/// <para>
	/// Note that the function returns before the process has finished initialization. If a required DLL cannot be located or fails to
	/// initialize, the process is terminated. To get the termination status of a process, call <c>GetExitCodeProcess</c>.
	/// </para>
	/// </returns>
	// BOOL WINAPI CreateProcess( _In_opt_ LPCTSTR lpApplicationName, _Inout_opt_ LPTSTR lpCommandLine, _In_opt_ LPSECURITY_ATTRIBUTES
	// lpProcessAttributes, _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, _In_ BOOL bInheritHandles, _In_ DWORD dwCreationFlags,
	// _In_opt_ LPVOID lpEnvironment, _In_opt_ LPCTSTR lpCurrentDirectory, _In_ LPSTARTUPINFO lpStartupInfo, _Out_ LPPROCESS_INFORMATION
	// lpProcessInformation); https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = true, CharSet = CharSet.Auto)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms682425")]
	[return: MarshalAs(UnmanagedType.Bool)]
	private static extern bool CreateProcess([Optional] string? lpApplicationName, [Optional] StringBuilder? lpCommandLine, [In, Optional] SECURITY_ATTRIBUTES? lpProcessAttributes,
		[In, Optional] SECURITY_ATTRIBUTES? lpThreadAttributes, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandles, CREATE_PROCESS dwCreationFlags,
		[In, Optional, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(NullTermStringArrayMarshaler), MarshalCookie = "Auto")] string[]? lpEnvironment,
		[Optional] string? lpCurrentDirectory, in STARTUPINFOEX lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);

	/// <summary>Retrieves the contents of the <c>STARTUPINFO</c> structure that was specified when the calling process was created.</summary>
	/// <param name="lpStartupInfo">A pointer to a <c>STARTUPINFO</c> structure that receives the startup information.</param>
	/// <returns>
	/// <para>This function does not return a value.</para>
	/// <para>
	/// If an error occurs, the ANSI version of this function ( <c>GetStartupInfoA</c>) can raise an exception. The Unicode version (
	/// <c>GetStartupInfoW</c>) does not fail.
	/// </para>
	/// </returns>
	// VOID WINAPI GetStartupInfo( _Out_ LPSTARTUPINFO lpStartupInfo); https://msdn.microsoft.com/en-us/library/windows/desktop/ms683230(v=vs.85).aspx
	[DllImport(Lib.Kernel32, SetLastError = false, CharSet = CharSet.Auto)]
	[PInvokeData("WinBase.h", MSDNShortId = "ms683230")]
	private static extern void GetStartupInfo(out STARTUPINFO_OUT lpStartupInfo);

	private static bool Is64bitOS() => !(0 == GetSystemWow64Directory(null, 0) && Win32Error.GetLastError() == Win32Error.ERROR_CALL_NOT_IMPLEMENTED);

	/// <summary>
	/// Represents app memory usage at a single point in time. This structure is used by the <c>PROCESS_INFORMATION_CLASS</c> class.
	/// </summary>
	// typedef struct _APP_MEMORY_INFORMATION { ULONG64 AvailableCommit; ULONG64 PrivateCommitUsage; ULONG64 PeakPrivateCommitUsage; ULONG64
	// TotalCommitUsage;} APP_MEMORY_INFORMATION, *PAPP_MEMORY_INFORMATION; https://msdn.microsoft.com/en-us/library/windows/desktop/mt767995(v=vs.85).aspx
	[PInvokeData("WinBase.h", MSDNShortId = "mt767995")]
	[StructLayout(LayoutKind.Sequential)]
	public struct APP_MEMORY_INFORMATION
	{
		/// <summary>Total commit available to the app.</summary>
		public ulong AvailableCommit;

		/// <summary>The app's usage of private commit.</summary>
		public ulong PrivateCommitUsage;

		/// <summary>The app's peak usage of private commit.</summary>
		public ulong PeakPrivateCommitUsage;

		/// <summary>The app's total usage of private plus shared commit.</summary>
		public ulong TotalCommitUsage;
	}

	/// <summary>
	/// Specifies the memory priority for a thread or process. This structure is used by the <c>GetProcessInformation</c>,
	/// <c>SetProcessInformation</c>, <c>GetThreadInformation</c>, and <c>SetThreadInformation</c> functions.
	/// </summary>
	/// <remarks>Initializes a new instance of the <see cref="MEMORY_PRIORITY_INFORMATION"/> struct.</remarks>
	/// <param name="memoryPriority">The memory priority for the thread or process.</param>
	// typedef struct _MEMORY_PRIORITY_INFORMATION { ULONG MemoryPriority;} MEMORY_PRIORITY_INFORMATION, *PMEMORY_PRIORITY_INFORMATION; https://msdn.microsoft.com/en-us/library/windows/desktop/hh448387(v=vs.85).aspx
	[PInvokeData("WinBase.h", MSDNShortId = "hh448387")]
	[StructLayout(LayoutKind.Sequential)]
	public struct MEMORY_PRIORITY_INFORMATION(MEMORY_PRIORITY memoryPriority)
	{
		/// <summary>
		/// <para>The memory priority for the thread or process. This member can be one of the following values.</para>
		/// <para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>MEMORY_PRIORITY_VERY_LOW1</term>
		/// <term>Very low memory priority.</term>
		/// </item>
		/// <item>
		/// <term>MEMORY_PRIORITY_LOW2</term>
		/// <term>Low memory priority.</term>
		/// </item>
		/// <item>
		/// <term>MEMORY_PRIORITY_MEDIUM3</term>
		/// <term>Medium memory priority.</term>
		/// </item>
		/// <item>
		/// <term>MEMORY_PRIORITY_BELOW_NORMAL4</term>
		/// <term>Below normal memory priority.</term>
		/// </item>
		/// <item>
		/// <term>MEMORY_PRIORITY_NORMAL5</term>
		/// <term>Normal memory priority. This is the default priority for all threads and processes on the system.</term>
		/// </item>
		/// </list>
		/// </para>
		/// </summary>
		public MEMORY_PRIORITY MemoryPriority = memoryPriority;
	}

	/// <summary>Represents a process or thread attribute identifier.</summary>
	/// <remarks>Initializes a new instance of the <see cref="PROC_THREAD_ATTRIBUTE"/> struct.</remarks>
	/// <param name="type">The attribute type.</param>
	/// <param name="Thread">if set to <c>true</c> this is thread specific.</param>
	/// <param name="Input">if set to <c>true</c> this is an input attribute.</param>
	/// <param name="Additive">if set to <c>true</c> this is additive.</param>
	[StructLayout(LayoutKind.Sequential)]
	public struct PROC_THREAD_ATTRIBUTE(PROC_THREAD_ATTRIBUTE.AttrType type, bool Thread, bool Input, bool Additive) : IEquatable<PROC_THREAD_ATTRIBUTE>, IEquatable<UIntPtr>
	{
		private readonly UIntPtr value = (UIntPtr)(((uint)type & PROC_THREAD_ATTRIBUTE_NUMBER) | (Thread ? PROC_THREAD_ATTRIBUTE_THREAD : 0) |
			(Input ? PROC_THREAD_ATTRIBUTE_INPUT : 0) | (Additive ? PROC_THREAD_ATTRIBUTE_ADDITIVE : 0));

		private const uint PROC_THREAD_ATTRIBUTE_NUMBER = 0x0000FFFF;
		private const uint PROC_THREAD_ATTRIBUTE_THREAD = 0x00010000;
		private const uint PROC_THREAD_ATTRIBUTE_INPUT = 0x00020000;
		private const uint PROC_THREAD_ATTRIBUTE_ADDITIVE = 0x00040000;

		private static readonly Dictionary<uint, Type?> typeLookup = [];

		static PROC_THREAD_ATTRIBUTE()
		{
			typeLookup.Add(PROC_THREAD_ATTRIBUTE_ALL_APPLICATION_PACKAGES_POLICY, null);
			typeLookup.Add(PROC_THREAD_ATTRIBUTE_CHILD_PROCESS_POLICY, typeof(ulong));
			typeLookup.Add(PROC_THREAD_ATTRIBUTE_DESKTOP_APP_POLICY, typeof(uint));
			typeLookup.Add(PROC_THREAD_ATTRIBUTE_GROUP_AFFINITY, typeof(GROUP_AFFINITY));
			typeLookup.Add(PROC_THREAD_ATTRIBUTE_HANDLE_LIST, typeof(HANDLE[]));
			typeLookup.Add(PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR, typeof(PROCESSOR_NUMBER));
			typeLookup.Add(PROC_THREAD_ATTRIBUTE_JOB_LIST, null);
			typeLookup.Add(PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, typeof(ulong));
			typeLookup.Add(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, typeof(HPROCESS));
			typeLookup.Add(PROC_THREAD_ATTRIBUTE_PREFERRED_NODE, typeof(uint));
			typeLookup.Add(PROC_THREAD_ATTRIBUTE_PROTECTION_LEVEL, typeof(uint));
			typeLookup.Add(PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES, typeof(SECURITY_CAPABILITIES));
			typeLookup.Add(PROC_THREAD_ATTRIBUTE_UMS_THREAD, typeof(UMS_CREATE_THREAD_ATTRIBUTES));
			typeLookup.Add(PROC_THREAD_ATTRIBUTE_WIN32K_FILTER, null);
		}

		/// <summary>Determines equality.</summary>
		/// <param name="attr">The attribute to compare.</param>
		/// <returns><see langword="true"/> if the value is equal to this instance.</returns>
		public bool Equals(PROC_THREAD_ATTRIBUTE attr) => value.Equals(attr.value);

		/// <summary>Determines equality.</summary>
		/// <param name="puint">The <see cref="UIntPtr"/> value.</param>
		/// <returns><see langword="true"/> if the value is equal to this instance.</returns>
		public bool Equals(UIntPtr puint) => value.Equals(puint);

		/// <summary>Determines whether the specified <see cref="object"/>, is equal to this instance.</summary>
		/// <param name="obj">The <see cref="object"/> to compare with this instance.</param>
		/// <returns><c>true</c> if the specified <see cref="object"/> is equal to this instance; otherwise, <c>false</c>.</returns>
		public override bool Equals(object? obj) => obj switch
		{
			PROC_THREAD_ATTRIBUTE pta => Equals(pta),
			UIntPtr up => Equals(up),
			uint ui => ui.Equals(this),
			_ => base.Equals(obj),
		};

		/// <summary>Returns a hash code for this instance.</summary>
		/// <returns>A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.</returns>
		public override int GetHashCode() => unchecked((int)value.ToUInt32());

		/// <summary>Performs an implicit conversion from <see cref="PROC_THREAD_ATTRIBUTE"/> to <see cref="uint"/>.</summary>
		/// <param name="pta">The PROC_THREAD_ATTRIBUTE.</param>
		/// <returns>The result of the conversion.</returns>
		public static implicit operator uint(PROC_THREAD_ATTRIBUTE pta) => pta.value.ToUInt32();

		/// <summary>A type specifier for an attribute.</summary>
		public enum AttrType : uint
		{
			/// <summary>
			/// The lpValue parameter is a pointer to a handle to a process to use instead of the calling process as the parent for the
			/// process being created. The process to use must have the PROCESS_CREATE_PROCESS access right.
			/// <para>
			/// Attributes inherited from the specified process include handles, the device map, processor affinity, priority, quotas, the
			/// process token, and job object. (Note that some attributes such as the debug port will come from the creating process, not the
			/// process specified by this handle.)
			/// </para>
			/// </summary>
			[CorrespondingType(typeof(HPROCESS))]
			ProcThreadAttributeParentProcess = 0,

			/// <summary>
			/// The lpValue parameter is a pointer to a list of handles to be inherited by the child process.
			/// <para>
			/// These handles must be created as inheritable handles and must not include pseudo handles such as those returned by the
			/// GetCurrentProcess or GetCurrentThread function.
			/// </para>
			/// <para>Note if you use this attribute, pass in a value of TRUE for the bInheritHandles parameter of the CreateProcess function.</para>
			/// </summary>
			[CorrespondingType(typeof(HANDLE[]))]
			ProcThreadAttributeHandleList = 2,

			/// <summary>
			/// The lpValue parameter is a pointer to a GROUP_AFFINITY structure that specifies the processor group affinity for the new thread.
			/// <para>Windows Server 2008 and Windows Vista: This value is not supported until Windows 7 and Windows Server 2008 R2.</para>
			/// </summary>
			[CorrespondingType(typeof(GROUP_AFFINITY))]
			ProcThreadAttributeGroupAffinity = 3,

			/// <summary>
			/// The lpValue parameter is a pointer to the node number of the preferred NUMA node for the new process.
			/// <para>Windows Server 2008 and Windows Vista: This value is not supported until Windows 7 and Windows Server 2008 R2.</para>
			/// </summary>
			[CorrespondingType(typeof(uint))]
			ProcThreadAttributePreferredNode = 4,

			/// <summary>
			/// The lpValue parameter is a pointer to a PROCESSOR_NUMBER structure that specifies the ideal processor for the new thread.
			/// <para>Windows Server 2008 and Windows Vista: This value is not supported until Windows 7 and Windows Server 2008 R2.</para>
			/// </summary>
			[CorrespondingType(typeof(PROCESSOR_NUMBER))]
			ProcThreadAttributeIdealProcessor = 5,

			/// <summary>
			/// The lpValue parameter is a pointer to a UMS_CREATE_THREAD_ATTRIBUTES structure that specifies a user-mode scheduling (UMS)
			/// thread context and a UMS completion list to associate with the thread.
			/// <para>
			/// After the UMS thread is created, the system queues it to the specified completion list. The UMS thread runs only when an
			/// application's UMS scheduler retrieves the UMS thread from the completion list and selects it to run. For more information,
			/// see User-Mode Scheduling.
			/// </para>
			/// <para>Windows Server 2008 and Windows Vista: This value is not supported until Windows 7 and Windows Server 2008 R2.</para>
			/// </summary>
			[CorrespondingType(typeof(UMS_CREATE_THREAD_ATTRIBUTES))]
			ProcThreadAttributeUmsThread = 6,

			/// <summary>
			/// The lpValue parameter is a pointer to a DWORD or DWORD64 that specifies the exploit mitigation policy for the child process.
			/// Starting in Windows 10, version 1703, this parameter can also be a pointer to a two-element DWORD64 array.
			/// <para>
			/// The specified policy overrides the policies set for the application and the system and cannot be changed after the child
			/// process starts running.
			/// </para>
			/// <para>Windows Server 2008 and Windows Vista: This value is not supported until Windows 7 and Windows Server 2008 R2.</para>
			/// <para>The DWORD or DWORD64 pointed to by lpValue can be one or more of the values listed in the remarks.</para>
			/// </summary>
			[CorrespondingType(typeof(uint))]
			[CorrespondingType(typeof(uint[]))]
			[CorrespondingType(typeof(ulong))]
			ProcThreadAttributeMitigationPolicy = 7,

			/// <summary>
			/// The lpValue parameter is a pointer to a SECURITY_CAPABILITIES structure that defines the security capabilities of an app
			/// container. If this attribute is set the new process will be created as an AppContainer process.
			/// <para>
			/// Windows 7, Windows Server 2008 R2, Windows Server 2008 and Windows Vista: This value is not supported until Windows 8 and
			/// Windows Server 2012.
			/// </para>
			/// </summary>
			[CorrespondingType(typeof(SECURITY_CAPABILITIES))]
			ProcThreadAttributeSecurityCapabilities = 9,

			/// <summary>
			/// The lpValue parameter is a pointer to a DWORD value of PROTECTION_LEVEL_SAME. This specifies the protection level of the
			/// child process to be the same as the protection level of its parent process.
			/// </summary>
			[CorrespondingType(typeof(uint))]
			ProcThreadAttributeProtectionLevel = 11,

			/// <summary/>
			ProcThreadAttributeJobList = 13,

			/// <summary>
			/// The lpValue parameter is a pointer to a DWORD or DWORD64 value that specifies the child process policy. THe policy specifies
			/// whether to allow a child process to be created.
			/// <para>For information on the possible values for the DWORD or DWORD64 to which lpValue points, see Remarks.</para>
			/// </summary>
			[CorrespondingType(typeof(uint))]
			[CorrespondingType(typeof(ulong))]
			ProcThreadAttributeChildProcessPolicy = 14,

			/// <summary/>
			ProcThreadAttributeAllApplicationPackagesPolicy = 15,

			/// <summary/>
			ProcThreadAttributeWin32kFilter = 16,

			/// <summary/>
			ProcThreadAttributeSafeOpenPromptOriginClaim = 17,

			/// <summary>
			/// This attribute is relevant only to win32 applications that have been converted to UWP packages by using the Desktop Bridge.
			/// <para>
			/// The lpValue parameter is a pointer to a DWORD value that specifies the desktop app policy. The policy specifies whether
			/// descendant processes should continue to run in the desktop environment.
			/// </para>
			/// <para>For information about the possible values for the DWORD to which lpValue points, see Remarks.</para>
			/// </summary>
			[CorrespondingType(typeof(uint))]
			ProcThreadAttributeDesktopAppPolicy = 18,
		}

		/// <summary>Gets the type associated with this attribute.</summary>
		public Type? ValidType => LookupType(this);

		/// <summary>Performs an implicit conversion from <see cref="PROC_THREAD_ATTRIBUTE"/> to <see cref="UIntPtr"/>.</summary>
		/// <param name="attr">The attribute.</param>
		/// <returns>The result of the conversion.</returns>
		public static implicit operator UIntPtr(PROC_THREAD_ATTRIBUTE attr) => attr.value;

		/// <summary>Lookups the type associated with an attribute.</summary>
		/// <param name="attr">The attribute.</param>
		/// <returns>The associated type, or <see langword="null"/> if not found.</returns>
		public static Type? LookupType(PROC_THREAD_ATTRIBUTE attr) => typeLookup.TryGetValue(attr, out Type? type) ? type : null;

		/// <summary>Undocumented.</summary>
		public static readonly PROC_THREAD_ATTRIBUTE PROC_THREAD_ATTRIBUTE_ALL_APPLICATION_PACKAGES_POLICY = new(AttrType.ProcThreadAttributeAllApplicationPackagesPolicy, false, true, false);

		/// <summary>
		/// The lpValue parameter is a pointer to a DWORD or DWORD64 value that specifies the child process policy. THe policy specifies
		/// whether to allow a child process to be created.For information on the possible values for the DWORD or DWORD64 to which lpValue
		/// points, see Remarks.
		/// </summary>
		public static readonly PROC_THREAD_ATTRIBUTE PROC_THREAD_ATTRIBUTE_CHILD_PROCESS_POLICY = new(AttrType.ProcThreadAttributeChildProcessPolicy, false, true, false);

		/// <summary>
		/// This attribute is relevant only to win32 applications that have been converted to UWP packages by using the Desktop Bridge. The
		/// lpValue parameter is a pointer to a DWORD value that specifies the desktop app policy. The policy specifies whether descendant
		/// processes should continue to run in the desktop environment.For information about the possible values for the DWORD to which
		/// lpValue points, see Remarks.
		/// </summary>
		public static readonly PROC_THREAD_ATTRIBUTE PROC_THREAD_ATTRIBUTE_DESKTOP_APP_POLICY = new(AttrType.ProcThreadAttributeDesktopAppPolicy, false, true, false);

		/// <summary>
		/// The lpValue parameter is a pointer to a GROUP_AFFINITY structure that specifies the processor group affinity for the new
		/// thread.Windows Server 2008 and Windows Vista: This value is not supported until Windows 7 and Windows Server 2008 R2.
		/// </summary>
		public static readonly PROC_THREAD_ATTRIBUTE PROC_THREAD_ATTRIBUTE_GROUP_AFFINITY = new(AttrType.ProcThreadAttributeGroupAffinity, true, true, false);

		/// <summary>
		/// The lpValue parameter is a pointer to a list of handles to be inherited by the child process.These handles must be created as
		/// inheritable handles and must not include pseudo handles such as those returned by the GetCurrentProcess or GetCurrentThread function.
		/// </summary>
		public static readonly PROC_THREAD_ATTRIBUTE PROC_THREAD_ATTRIBUTE_HANDLE_LIST = new(AttrType.ProcThreadAttributeHandleList, false, true, false);

		/// <summary>
		/// The lpValue parameter is a pointer to a PROCESSOR_NUMBER structure that specifies the ideal processor for the new thread.Windows
		/// Server 2008 and Windows Vista: This value is not supported until Windows 7 and Windows Server 2008 R2.
		/// </summary>
		public static readonly PROC_THREAD_ATTRIBUTE PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR = new(AttrType.ProcThreadAttributeIdealProcessor, true, true, false);

		/// <summary>Undocumented.</summary>
		public static readonly PROC_THREAD_ATTRIBUTE PROC_THREAD_ATTRIBUTE_JOB_LIST = new(AttrType.ProcThreadAttributeJobList, false, true, false);

		/// <summary>
		/// The lpValue parameter is a pointer to a DWORD or DWORD64 that specifies the exploit mitigation policy for the child process.
		/// Starting in Windows 10, version 1703, this parameter can also be a pointer to a two-element DWORD64 array.The specified policy
		/// overrides the policies set for the application and the system and cannot be changed after the child process starts running.
		/// Windows Server 2008 and Windows Vista: This value is not supported until Windows 7 and Windows Server 2008 R2.The DWORD or
		/// DWORD64 pointed to by lpValue can be one or more of the values listed in the remarks.
		/// </summary>
		public static readonly PROC_THREAD_ATTRIBUTE PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY = new(AttrType.ProcThreadAttributeMitigationPolicy, false, true, false);

		/// <summary>
		/// The lpValue parameter is a pointer to a handle to a process to use instead of the calling process as the parent for the process
		/// being created. The process to use must have the PROCESS_CREATE_PROCESS access right.Attributes inherited from the specified
		/// process include handles, the device map, processor affinity, priority, quotas, the process token, and job object. (Note that some
		/// attributes such as the debug port will come from the creating process, not the process specified by this handle.)
		/// </summary>
		public static readonly PROC_THREAD_ATTRIBUTE PROC_THREAD_ATTRIBUTE_PARENT_PROCESS = new(AttrType.ProcThreadAttributeParentProcess, false, true, false);

		/// <summary>
		/// The lpValue parameter is a pointer to the node number of the preferred NUMA node for the new process.Windows Server 2008 and
		/// Windows Vista: This value is not supported until Windows 7 and Windows Server 2008 R2.
		/// </summary>
		public static readonly PROC_THREAD_ATTRIBUTE PROC_THREAD_ATTRIBUTE_PREFERRED_NODE = new(AttrType.ProcThreadAttributePreferredNode, false, true, false);

		/// <summary>
		/// The lpValue parameter is a pointer to a DWORD value of PROTECTION_LEVEL_SAME. This specifies the protection level of the child
		/// process to be the same as the protection level of its parent process.
		/// </summary>
		public static readonly PROC_THREAD_ATTRIBUTE PROC_THREAD_ATTRIBUTE_PROTECTION_LEVEL = new(AttrType.ProcThreadAttributeProtectionLevel, false, true, false);

		/// <summary>
		/// The lpValue parameter is a pointer to a SECURITY_CAPABILITIES structure that defines the security capabilities of an app
		/// container. If this attribute is set the new process will be created as an AppContainer process.Windows 7, Windows Server 2008 R2,
		/// Windows Server 2008 and Windows Vista: This value is not supported until Windows 8 and Windows Server 2012.
		/// </summary>
		public static readonly PROC_THREAD_ATTRIBUTE PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES = new(AttrType.ProcThreadAttributeSecurityCapabilities, false, true, false);

		/// <summary>
		/// The lpValue parameter is a pointer to a UMS_CREATE_THREAD_ATTRIBUTES structure that specifies a user-mode scheduling (UMS) thread
		/// context and a UMS completion list to associate with the thread. After the UMS thread is created, the system queues it to the
		/// specified completion list. The UMS thread runs only when an application's UMS scheduler retrieves the UMS thread from the
		/// completion list and selects it to run. For more information, see User-Mode Scheduling.Windows Server 2008 and Windows
		/// Vista: This value is not supported until Windows 7 and Windows Server 2008 R2.
		/// </summary>
		public static readonly PROC_THREAD_ATTRIBUTE PROC_THREAD_ATTRIBUTE_UMS_THREAD = new(AttrType.ProcThreadAttributeUmsThread, true, true, false);

		/// <summary>Undocumented.</summary>
		public static readonly PROC_THREAD_ATTRIBUTE PROC_THREAD_ATTRIBUTE_WIN32K_FILTER = new(AttrType.ProcThreadAttributeWin32kFilter, false, true, false);

		/// <summary>Implements the operator ==.</summary>
		/// <param name="left">The left.</param>
		/// <param name="right">The right.</param>
		/// <returns>The result of the operator.</returns>
		public static bool operator ==(PROC_THREAD_ATTRIBUTE left, PROC_THREAD_ATTRIBUTE right) => left.Equals(right);

		/// <summary>Implements the operator !=.</summary>
		/// <param name="left">The left.</param>
		/// <param name="right">The right.</param>
		/// <returns>The result of the operator.</returns>
		public static bool operator !=(PROC_THREAD_ATTRIBUTE left, PROC_THREAD_ATTRIBUTE right) => !left.Equals(right);
	}

	/// <summary>
	/// Contains dynamic exception handling continuation targets. The SetProcessDynamicEHContinuationTargets function uses this structure.
	/// </summary>
	// https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-process_dynamic_eh_continuation_target typedef struct
	// _PROCESS_DYNAMIC_EH_CONTINUATION_TARGET { ULONG_PTR TargetAddress; ULONG_PTR Flags; } PROCESS_DYNAMIC_EH_CONTINUATION_TARGET, *PPROCESS_DYNAMIC_EH_CONTINUATION_TARGET;
	[PInvokeData("winnt.h", MSDNShortId = "NS:winnt._PROCESS_DYNAMIC_EH_CONTINUATION_TARGET")]
	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
	public struct PROCESS_DYNAMIC_EH_CONTINUATION_TARGET
	{
		/// <summary>The address of a dynamic exception handling continuation target.</summary>
		public IntPtr TargetAddress;

		private IntPtr _Flags;

		/// <summary>
		/// <para>Flags that apply to the dynamic exception handling continuation target in TargetAddress.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>DYNAMIC_EH_CONTINUATION_TARGET_ADD 0x00000001UL</term>
		/// <term>
		/// Dynamic exception handling continuation target should be added. If this flag is not set, the target is removed. This is an input flag.
		/// </term>
		/// </item>
		/// <item>
		/// <term>DYNAMIC_EH_CONTINUATION_TARGET_PROCESSED 0x00000002UL</term>
		/// <term>
		/// Dynamic exception handling continuation target has been successfully processed (either added or removed). This is an output flag
		/// used to report which targets were successfully processed when processing an array of multiple targets.
		/// </term>
		/// </item>
		/// </list>
		/// </summary>
		public DYNAMIC_EH_CONTINUATION_TARGET Flags { get => (DYNAMIC_EH_CONTINUATION_TARGET)_Flags.ToInt32(); set => _Flags = new IntPtr((int)value); }
	}

	/// <summary>
	/// Contains information about a newly created process and its primary thread. It is used with the <c>CreateProcess</c>,
	/// <c>CreateProcessAsUser</c>, <c>CreateProcessWithLogonW</c>, or <c>CreateProcessWithTokenW</c> function.
	/// </summary>
	// typedef struct _PROCESS_INFORMATION { HANDLE hProcess; HANDLE hThread; DWORD dwProcessId; DWORD dwThreadId;} PROCESS_INFORMATION,
	// *LPPROCESS_INFORMATION; https://msdn.microsoft.com/en-us/library/windows/desktop/ms684873(v=vs.85).aspx
	[PInvokeData("WinBase.h", MSDNShortId = "ms684873")]
	[StructLayout(LayoutKind.Sequential)]
	public struct PROCESS_INFORMATION
	{
		/// <summary>
		/// A handle to the newly created process. The handle is used to specify the process in all functions that perform operations on the
		/// process object.
		/// </summary>
		public HPROCESS hProcess;

		/// <summary>
		/// A handle to the primary thread of the newly created process. The handle is used to specify the thread in all functions that
		/// perform operations on the thread object.
		/// </summary>
		public HTHREAD hThread;

		/// <summary>
		/// A value that can be used to identify a process. The value is valid from the time the process is created until all handles to the
		/// process are closed and the process object is freed; at this point, the identifier may be reused.
		/// </summary>
		public uint dwProcessId;

		/// <summary>
		/// A value that can be used to identify a thread. The value is valid from the time the thread is created until all handles to the
		/// thread are closed and the thread object is freed; at this point, the identifier may be reused.
		/// </summary>
		public uint dwThreadId;
	}

	/// <summary>Specifies how the system handles positive leap seconds.</summary>
	// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-process_leap_second_info typedef struct
	// _PROCESS_LEAP_SECOND_INFO { ULONG Flags; ULONG Reserved; } PROCESS_LEAP_SECOND_INFO, *PPROCESS_LEAP_SECOND_INFO;
	[PInvokeData("processthreadsapi.h", MSDNShortId = "NS:processthreadsapi._PROCESS_LEAP_SECOND_INFO")]
	[StructLayout(LayoutKind.Sequential)]
	public struct PROCESS_LEAP_SECOND_INFO
	{
		/// <summary>
		/// <para>Currently, the only valid flag is <c>PROCESS_LEAP_SECOND_INFO_FLAG_ENABLE_SIXTY_SECOND</c>. That flag is described below.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <description>PROCESS_LEAP_SECOND_INFO_FLAG_ENABLE_SIXTY_SECOND</description>
		/// <description>
		/// This value changes the way positive leap seconds are handled by system. Specifically, it changes how the seconds field during a
		/// positive leap second is handled by the system. If this value is used, then the positive leap second will be shown (For example:
		/// 23:59:59 -&gt; 23:59:60 -&gt; 00:00:00. If this value is not used, then "sixty seconds" is disabled, and the 59th second
		/// preceding a positive leap second will be shown for 2 seconds with the milliseconds value ticking twice as slow. So 23:59:59 -&gt;
		/// 23:59:59.500 -&gt; 00:00:00, which takes 2 seconds in wall clock time. Disabling "sixty second" can help with legacy apps that do
		/// not support seeing the seconds value as 60 during the positive leap second. Such apps may crash or misbehave. Therefore, in these
		/// cases, we display the 59th second for twice as long during the positive leap second. Note that this setting is per-process, and
		/// does not persist if the process is restarted. Developers should test their app for compatibility with seeing the system return
		/// "60", and add a call to their app startup routines to either enable or disable "sixty seconds". "Sixty seconds" is disabled by
		/// default for each process. Obviously, this setting has no effect if leap seconds are disabled system-wide, because then the system
		/// will never even encounter a leap second.
		/// </description>
		/// </item>
		/// </list>
		/// </summary>
		public PROCESS_LEAP_SECOND_INFO_FLAGS Flags;

		/// <summary>Reserved for future use</summary>
		public uint Reserved;
	}

	/// <summary>
	/// Specifies the architecture of a process and if that architecture of code can run in user mode, kernel mode, and/or under WoW64 on the
	/// host operating system.
	/// </summary>
	// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-process_machine_information typedef struct
	// _PROCESS_MACHINE_INFORMATION { USHORT ProcessMachine; USHORT Res0; MACHINE_ATTRIBUTES MachineAttributes; } PROCESS_MACHINE_INFORMATION;
	[PInvokeData("processthreadsapi.h", MSDNShortId = "NS:processthreadsapi._PROCESS_MACHINE_INFORMATION")]
	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
	public struct PROCESS_MACHINE_INFORMATION
	{
		/// <summary>
		/// An IMAGE_FILE_MACHINE_* value indicating the architecture of the associated process. See the list of architecture values in Image
		/// File Machine Constants.
		/// </summary>
		public IMAGE_FILE_MACHINE ProcessMachine;

		/// <summary>Reserved.</summary>
		public ushort Res0;

		/// <summary>
		/// A value from the MACHINE_ATTRIBUTES enumeration indicating if the process’s architecture can run in user mode, kernel mode,
		/// and/or under WOW64 on the host operating system.
		/// </summary>
		public MACHINE_ATTRIBUTES MachineAttributes;
	}

	/// <summary>
	/// Allows applications to configure a process to terminate if an allocation fails to commit memory. This structure is used by the
	/// <c>PROCESS_INFORMATION_CLASS</c> class.
	/// </summary>
	// typedef struct _PROCESS_MEMORY_EXHAUSTION_INFO { USHORT Version; USHORT Reserved; PROCESS_MEMORY_EXHAUSTION_TYPE Type; ULONG_PTR
	// Value;} PROCESS_MEMORY_EXHAUSTION_INFO, *PPROCESS_MEMORY_EXHAUSTION_INFO;// https://msdn.microsoft.com/en-us/library/windows/desktop/mt767997(v=vs.85).aspx
	[PInvokeData("WinBase.h", MSDNShortId = "mt767997")]
	[StructLayout(LayoutKind.Sequential)]
	public struct PROCESS_MEMORY_EXHAUSTION_INFO
	{
		/// <summary>Version should be set to <c>PME_CURRENT_VERSION</c>.</summary>
		public ushort Version;

		/// <summary>Reserved.</summary>
		public ushort Reserved;

		/// <summary>
		/// <para>Type of failure.</para>
		/// <para>Type should be set to <c>PMETypeFailFastOnCommitFailure</c> (this is the only type available).</para>
		/// </summary>
		public PROCESS_MEMORY_EXHAUSTION_TYPE Type;

		/// <summary>
		/// <para>Used to turn the feature on or off.</para>
		/// <para>
		/// <list type="table">
		/// <listheader>
		/// <term>Function</term>
		/// <term>Setting</term>
		/// </listheader>
		/// <item>
		/// <term>Enable</term>
		/// <term>PME_FAILFAST_ON_COMMIT_FAIL_ENABLE</term>
		/// </item>
		/// <item>
		/// <term>Disable</term>
		/// <term>PME_FAILFAST_ON_COMMIT_FAIL_DISABLE</term>
		/// </item>
		/// </list>
		/// </para>
		/// </summary>
		public nuint Value;
	}

	/// <summary>
	/// Contains process mitigation policy settings for Address Space Randomization Layout (ASLR). The <c>GetProcessMitigationPolicy</c> and
	/// <c>SetProcessMitigationPolicy</c> functions use this structure.
	/// </summary>
	// typedef struct _PROCESS_MITIGATION_ASLR_POLICY { union { DWORD Flags; struct { DWORD EnableBottomUpRandomization : 1; DWORD
	// EnableForceRelocateImages : 1; DWORD EnableHighEntropy : 1; DWORD DisallowStrippedImages : 1; DWORD ReservedFlags : 28; }; };} PROCESS_MITIGATION_ASLR_POLICY,
	// *PPROCESS_MITIGATION_ASLR_POLICY; https://msdn.microsoft.com/en-us/library/windows/desktop/hh769086(v=vs.85).aspx
	[PInvokeData("WinNT.h", MSDNShortId = "hh769086")]
	[StructLayout(LayoutKind.Sequential)]
	public struct PROCESS_MITIGATION_ASLR_POLICY
	{
		/// <summary>The flags</summary>
		public PROCESS_MITIGATION_ASLR_POLICY_FLAGS Flags;
	}

	/// <summary>Contains process mitigation policy settings for the loading of images depending on the signatures for the image.</summary>
	// typedef struct _PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY { union { DWORD Flags; struct { DWORD MicrosoftSignedOnly :1; DWORD
	// StoreSignedOnly :1; DWORD MitigationOptIn :1; DWORD ReservedFlags :29; }; };} PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY,
	// *PPROCESS_MITIGATION_BINARY_SIGNATURE_POLICY; https://msdn.microsoft.com/en-us/library/windows/desktop/mt706242(v=vs.85).aspx
	[PInvokeData("WinNT.h", MSDNShortId = "mt706242")]
	[StructLayout(LayoutKind.Sequential)]
	public struct PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY
	{
		/// <summary>The flags</summary>
		public PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY_FLAGS Flags;
	}

	/// <summary>Stores policy information about creating child processes.</summary>
	// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ntddk/ns-ntddk-_process_mitigation_child_process_policy
	[PInvokeData("WinNT.h", MSDNShortId = "")]
	[StructLayout(LayoutKind.Sequential)]
	public struct PROCESS_MITIGATION_CHILD_PROCESS_POLICY
	{
		/// <summary>The flags</summary>
		public PROCESS_MITIGATION_CHILD_PROCESS_POLICY_FLAGS Flags;
	}

	/// <summary>
	/// Contains process mitigation policy settings for Control Flow Guard (CFG). The <c>GetProcessMitigationPolicy</c> and
	/// <c>SetProcessMitigationPolicy</c> functions use this structure.
	/// </summary>
	// typedef struct _PROCESS_MITIGATION_CONTROL_FLOW_GUARD_POLICY { union { DWORD Flags; struct { DWORD EnableControlFlowGuard :1; DWORD
	// EnableExportSuppression :1; DWORD StrictMode :1; DWORD ReservedFlags :29; }; };} PROCESS_MITIGATION_CONTROL_FLOW_GUARD_POLICY,
	// *PPROCESS_MITIGATION_CONTROL_FLOW_GUARD_POLICY; https://msdn.microsoft.com/en-us/library/windows/desktop/mt654121(v=vs.85).aspx
	[PInvokeData("WinNT.h", MSDNShortId = "mt654121")]
	[StructLayout(LayoutKind.Sequential)]
	public struct PROCESS_MITIGATION_CONTROL_FLOW_GUARD_POLICY
	{
		/// <summary>The flags</summary>
		public PROCESS_MITIGATION_CONTROL_FLOW_GUARD_POLICY_FLAGS Flags;
	}

	/// <summary>
	/// Contains process mitigation policy settings for data execution prevention (DEP). The <c>GetProcessMitigationPolicy</c> and
	/// <c>SetProcessMitigationPolicy</c> functions use this structure.
	/// </summary>
	// typedef struct _PROCESS_MITIGATION_DEP_POLICY { union { DWORD Flags; struct { DWORD Enable : 1; DWORD DisableAtlThunkEmulation : 1;
	// DWORD ReservedFlags : 30; }; }; BOOLEAN Permanent;} PROCESS_MITIGATION_DEP_POLICY, *PPROCESS_MITIGATION_DEP_POLICY; https://msdn.microsoft.com/en-us/library/windows/desktop/hh769087(v=vs.85).aspx
	[PInvokeData("WinNT.h", MSDNShortId = "hh769087")]
	[StructLayout(LayoutKind.Sequential, Pack = 4)]
	public struct PROCESS_MITIGATION_DEP_POLICY
	{
		/// <summary>The flags</summary>
		public PROCESS_MITIGATION_DEP_POLICY_FLAGS Flags;

		/// <summary>DEP is permanently enabled and cannot be disabled if this field is set to TRUE.</summary>
		[MarshalAs(UnmanagedType.U1)]
		public bool Permanent;
	}

	/// <summary>Contains process mitigation policy settings for restricting dynamic code generation and modification.</summary>
	// typedef struct _PROCESS_MITIGATION_DYNAMIC_CODE_POLICY { union { DWORD Flags; struct { DWORD ProhibitDynamicCode :1; DWORD
	// AllowThreadOptOut :1; DWORD AllowRemoteDowngrade :1; DWORD ReservedFlags :30; }; };} PROCESS_MITIGATION_DYNAMIC_CODE_POLICY,
	// *PPROCESS_MITIGATION_DYNAMIC_CODE_POLICY; https://msdn.microsoft.com/en-us/library/windows/desktop/mt706243(v=vs.85).aspx
	[PInvokeData("WinNT.h", MSDNShortId = "mt706243")]
	[StructLayout(LayoutKind.Sequential)]
	public struct PROCESS_MITIGATION_DYNAMIC_CODE_POLICY
	{
		/// <summary>The flags</summary>
		public PROCESS_MITIGATION_DYNAMIC_CODE_POLICY_FLAGS Flags;
	}

	/// <summary>
	/// Contains process mitigation policy settings for legacy extension point DLLs. The <c>GetProcessMitigationPolicy</c> and
	/// <c>SetProcessMitigationPolicy</c> functions use this structure.
	/// </summary>
	// typedef struct _PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY { union { DWORD Flags; struct { DWORD DisableExtensionPoints : 1;
	// DWORD ReservedFlags : 31; }; };} PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY,
	// *PPROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY; https://msdn.microsoft.com/en-us/library/windows/desktop/jj200586(v=vs.85).aspx
	[PInvokeData("Winnt.h", MSDNShortId = "jj200586")]
	[StructLayout(LayoutKind.Sequential)]
	public struct PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY
	{
		/// <summary>The flags</summary>
		public PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY_FLAGS Flags;
	}

	/// <summary>Contains process mitigation policy settings for the loading of non-system fonts.</summary>
	// typedef struct _PROCESS_MITIGATION_FONT_DISABLE_POLICY { union { DWORD Flags; struct { DWORD DisableNonSystemFonts :1; DWORD
	// AuditNonSystemFontLoading :1; DWORD ReservedFlags :30; }; };} PROCESS_MITIGATION_FONT_DISABLE_POLICY,
	// *PPROCESS_MITIGATION_FONT_DISABLE_POLICY; https://msdn.microsoft.com/en-us/library/windows/desktop/mt706244(v=vs.85).aspx
	[PInvokeData("WinNT.h", MSDNShortId = "mt706244")]
	[StructLayout(LayoutKind.Sequential)]
	public struct PROCESS_MITIGATION_FONT_DISABLE_POLICY
	{
		/// <summary>The flags</summary>
		public PROCESS_MITIGATION_FONT_DISABLE_POLICY_FLAGS Flags;
	}

	/// <summary>Contains process mitigation policy settings for the loading of images from a remote device.</summary>
	// typedef struct _PROCESS_MITIGATION_IMAGE_LOAD_POLICY { union { DWORD Flags; struct { DWORD NoRemoteImages :1; DWORD
	// NoLowMandatoryLabelImages :1; DWORD PreferSystem32Images :1; DWORD ReservedFlags :29; }; };} PROCESS_MITIGATION_IMAGE_LOAD_POLICY,
	// *PPROCESS_MITIGATION_IMAGE_LOAD_POLICY; https://msdn.microsoft.com/en-us/library/windows/desktop/mt706245(v=vs.85).aspx
	[PInvokeData("WinNT.h", MSDNShortId = "mt706245")]
	[StructLayout(LayoutKind.Sequential)]
	public struct PROCESS_MITIGATION_IMAGE_LOAD_POLICY
	{
		/// <summary>The flags</summary>
		public PROCESS_MITIGATION_IMAGE_LOAD_POLICY_FLAGS Flags;
	}

	/// <summary>Stores information about process mitigation policy.</summary>
	// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ntddk/ns-ntddk-_process_mitigation_payload_restriction_policy
	[PInvokeData("WinNT.h", MSDNShortId = "")]
	[StructLayout(LayoutKind.Sequential)]
	public struct PROCESS_MITIGATION_PAYLOAD_RESTRICTION_POLICY
	{
		/// <summary>The flags</summary>
		public PROCESS_MITIGATION_PAYLOAD_RESTRICTION_POLICY_FLAGS Flags;
	}

	/// <summary>Used to impose new behavior on handle references that are not valid.</summary>
	// typedef struct _PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY { union { DWORD Flags; struct { DWORD
	// RaiseExceptionOnInvalidHandleReference : 1; DWORD HandleExceptionsPermanentlyEnabled : 1; DWORD ReservedFlags : 30; }; };} PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY,
	// *PPROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY; https://msdn.microsoft.com/en-us/library/windows/desktop/hh871471(v=vs.85).aspx
	[PInvokeData("WinNT.h", MSDNShortId = "hh871471")]
	[StructLayout(LayoutKind.Sequential)]
	public struct PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY
	{
		/// <summary>The flags</summary>
		public PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY_FLAGS Flags;
	}

	/// <summary>Used to impose restrictions on what system calls can be invoked by a process.</summary>
	// typedef struct _PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY { union { DWORD Flags; struct { DWORD DisallowWin32kSystemCalls : 1;
	// DWORD ReservedFlags : 31; }; };} PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY, *PPROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY; https://msdn.microsoft.com/en-us/library/windows/desktop/hh871472(v=vs.85).aspx
	[PInvokeData("WinNT.h", MSDNShortId = "hh871472")]
	[StructLayout(LayoutKind.Sequential)]
	public struct PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY
	{
		/// <summary>The flags</summary>
		public PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY_FLAGS Flags;
	}

	/// <summary>This structure is not supported.</summary>
	// https://msdn.microsoft.com/en-us/library/windows/hardware/mt843942(v=vs.85).aspx
	[PInvokeData("WinNT.h", MSDNShortId = "mt843942")]
	[StructLayout(LayoutKind.Sequential)]
	public struct PROCESS_MITIGATION_SYSTEM_CALL_FILTER_POLICY
	{
		/// <summary>Undocumented.</summary>
		public uint FilterId; // Only lowest 4 bits
	}

	/// <summary>Specifies the throttling policies and how to apply them to a target process when that process is subject to power management.</summary>
	/// <remarks>Initializes a new instance of the <see cref="PROCESS_POWER_THROTTLING_STATE"/> struct.</remarks>
	/// <param name="controlMask">The control mask.</param>
	/// <param name="stateMask">The state mask.</param>
	// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-process_power_throttling_state typedef
	// struct _PROCESS_POWER_THROTTLING_STATE { ULONG Version; ULONG ControlMask; ULONG StateMask; } PROCESS_POWER_THROTTLING_STATE, *PPROCESS_POWER_THROTTLING_STATE;
	[PInvokeData("processthreadsapi.h", MSDNShortId = "394B6509-849C-4B4C-9A46-AF5011A03585")]
	[StructLayout(LayoutKind.Sequential)]
	public struct PROCESS_POWER_THROTTLING_STATE(PROCESS_POWER_THROTTLING_MASK controlMask, PROCESS_POWER_THROTTLING_MASK stateMask)
	{
		/// <summary/>
		public const uint PROCESS_POWER_THROTTLING_CURRENT_VERSION = 1;

		/// <summary>
		/// <para>The version of the <c>PROCESS_POWER_THROTTLING_STATE</c> structure.</para>
		/// <para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>PROCESS_POWER_THROTTLING_CURRENT_VERSION</term>
		/// <term>The current version.</term>
		/// </item>
		/// </list>
		/// </para>
		/// </summary>
		public uint Version = PROCESS_POWER_THROTTLING_CURRENT_VERSION;

		/// <summary>
		/// <para>This field enables the caller to take control of the power throttling mechanism.</para>
		/// <para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>PROCESS_POWER_THROTTLING_EXECUTION_SPEED</term>
		/// <term>Manages the execution speed of the process.</term>
		/// </item>
		/// </list>
		/// </para>
		/// </summary>
		public PROCESS_POWER_THROTTLING_MASK ControlMask = controlMask;

		/// <summary>
		/// <para>Manages the power throttling mechanism on/off state.</para>
		/// <para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>PROCESS_POWER_THROTTLING_EXECUTION_SPEED</term>
		/// <term>Manages the execution speed of the process.</term>
		/// </item>
		/// </list>
		/// </para>
		/// </summary>
		public PROCESS_POWER_THROTTLING_MASK StateMask = stateMask;
	}

	/// <summary>Specifies whether Protected Process Light (PPL) is enabled.</summary>
	// typedef struct _PROCESS_PROTECTION_LEVEL_INFORMATION { DWORD ProtectionLevel;} PROCESS_PROTECTION_LEVEL_INFORMATION,
	// *PPROCESS_PROTECTION_LEVEL_INFORMATION;// https://msdn.microsoft.com/en-us/library/windows/desktop/mt823702(v=vs.85).aspx
	[PInvokeData("Processthreadsapi.h", MSDNShortId = "mt823702")]
	[StructLayout(LayoutKind.Sequential)]
	public struct PROCESS_PROTECTION_LEVEL_INFORMATION
	{
		/// <summary>
		/// <para>The one of the following values.</para>
		/// <para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>PROTECTION_LEVEL_WINTCB_LIGHT</term>
		/// <term>For internal use only.</term>
		/// </item>
		/// <item>
		/// <term>PROTECTION_LEVEL_WINDOWS</term>
		/// <term>For internal use only.</term>
		/// </item>
		/// <item>
		/// <term>PROTECTION_LEVEL_WINDOWS_LIGHT</term>
		/// <term>For internal use only.</term>
		/// </item>
		/// <item>
		/// <term>PROTECTION_LEVEL_ANTIMALWARE_LIGHT</term>
		/// <term>For internal use only.</term>
		/// </item>
		/// <item>
		/// <term>PROTECTION_LEVEL_LSA_LIGHT</term>
		/// <term>For internal use only.</term>
		/// </item>
		/// <item>
		/// <term>PROTECTION_LEVEL_WINTCB</term>
		/// <term>Not implemented.</term>
		/// </item>
		/// <item>
		/// <term>PROTECTION_LEVEL_CODEGEN_LIGHT</term>
		/// <term>Not implemented.</term>
		/// </item>
		/// <item>
		/// <term>PROTECTION_LEVEL_AUTHENTICODE</term>
		/// <term>Not implemented.</term>
		/// </item>
		/// <item>
		/// <term>PROTECTION_LEVEL_PPL_APP</term>
		/// <term>The process is a third party app that is using process protection.</term>
		/// </item>
		/// <item>
		/// <term>PROTECTION_LEVEL_NONE</term>
		/// <term>The process is not protected.</term>
		/// </item>
		/// </list>
		/// </para>
		/// </summary>
		public PROTECTION_LEVEL ProtectionLevel;
	}

	/// <summary>Represents a logical processor in a processor group.</summary>
	/// <remarks>Initializes a new instance of the <see cref="PROCESSOR_NUMBER"/> struct.</remarks>
	/// <param name="processorGroup">The processor group to which the logical processor is assigned.</param>
	/// <param name="logicalProcessor">The number of the logical processor relative to the group.</param>
	[PInvokeData("WinNT.h", MSDNShortId = "dd405505")]
	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public struct PROCESSOR_NUMBER(ushort processorGroup, byte logicalProcessor)
	{
		/// <summary>The processor group to which the logical processor is assigned.</summary>
		public ushort Group = processorGroup;

		/// <summary>The number of the logical processor relative to the group.</summary>
		public byte Number = logicalProcessor;

		/// <summary>This parameter is reserved.</summary>
		public byte Reserved = 0;
	}

	/// <summary>
	/// Specifies the window station, desktop, standard handles, and appearance of the main window for a process at creation time.
	/// </summary>
	/// <remarks>
	/// <para>
	/// For graphical user interface (GUI) processes, this information affects the first window created by the CreateWindow function and
	/// shown by the ShowWindow function. For console processes, this information affects the console window if a new console is created for
	/// the process. A process can use the GetStartupInfo function to retrieve the <c>STARTUPINFO</c> structure specified when the process
	/// was created.
	/// </para>
	/// <para>
	/// If a GUI process is being started and neither STARTF_FORCEONFEEDBACK or STARTF_FORCEOFFFEEDBACK is specified, the process feedback
	/// cursor is used. A GUI process is one whose subsystem is specified as "windows."
	/// </para>
	/// <para>
	/// If a process is launched from the taskbar or jump list, the system sets <c>hStdOutput</c> to a handle to the monitor that contains
	/// the taskbar or jump list used to launch the process. To retrieve this handle, use GetStartupInfo to retrieve the <c>STARTUPINFO</c>
	/// structure and check that <c>hStdOutput</c> is set. If so, use GetMonitorInfo to check whether <c>hStdOutput</c> is a valid monitor
	/// handle (HMONITOR). The process can then use the handle to position its windows.
	/// </para>
	/// <para>
	/// If the <c>STARTF_UNTRUSTEDSOURCE</c> flag is set in the in the <c>STARTUPINFO</c> structure returned by the GetStartupInfo function,
	/// then applications should be aware that the command line is untrusted. If this flag is set, applications should disable potentially
	/// dangerous features such as macros, downloaded content, and automatic printing. This flag is optional. Applications that call
	/// CreateProcess are encouraged to set this flag when launching a program with a untrusted command line so that the created process can
	/// apply appropriate policy.
	/// </para>
	/// <para>
	/// The <c>STARTF_UNTRUSTEDSOURCE</c> flag is supported starting in Windows Vista, but it is not defined in the SDK header files prior to
	/// the Windows 10 SDK. To use the flag in versions prior to Windows 10, you can define it manually in your program.
	/// </para>
	/// <para>Examples</para>
	/// <para>For an example, see Creating Processes.</para>
	/// </remarks>
	// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-_startupinfoa typedef struct _STARTUPINFOA {
	// DWORD cb; LPSTR lpReserved; LPSTR lpDesktop; LPSTR lpTitle; DWORD dwX; DWORD dwY; DWORD dwXSize; DWORD dwYSize; DWORD dwXCountChars;
	// DWORD dwYCountChars; DWORD dwFillAttribute; DWORD dwFlags; WORD wShowWindow; WORD cbReserved2; LPBYTE lpReserved2; HANDLE hStdInput;
	// HANDLE hStdOutput; HANDLE hStdError; } STARTUPINFOA, *LPSTARTUPINFOA;
	[PInvokeData("processthreadsapi.h", MSDNShortId = "cf4b795c-52c1-4573-8328-99ee13f68bb3")]
	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
	public struct STARTUPINFO
	{
		/// <summary>The size of the structure, in bytes.</summary>
		public uint cb;

		/// <summary>Reserved; must be NULL.</summary>
		public IntPtr lpReserved;

		/// <summary>
		/// The name of the desktop, or the name of both the desktop and window station for this process. A backslash in the string indicates
		/// that the string includes both the desktop and window station names.
		/// <para>
		/// For more information, see <a href="https://msdn.microsoft.com/45016619-ed11-4b0c-84e3-f8662553c64d">Thread Connection to a Desktop</a>.
		/// </para>
		/// </summary>
		[MarshalAs(UnmanagedType.LPTStr)]
		public string? lpDesktop;

		/// <summary>
		/// For console processes, this is the title displayed in the title bar if a new console window is created. If NULL, the name of the
		/// executable file is used as the window title instead. This parameter must be NULL for GUI or console processes that do not create
		/// a new console window.
		/// </summary>
		[MarshalAs(UnmanagedType.LPTStr)]
		public string? lpTitle;

		/// <summary>
		/// <para>
		/// If <c>dwFlags</c> specifies STARTF_USEPOSITION, this member is the x offset of the upper left corner of a window if a new window
		/// is created, in pixels. Otherwise, this member is ignored.
		/// </para>
		/// <para>
		/// The offset is from the upper left corner of the screen. For GUI processes, the specified position is used the first time the new
		/// process calls CreateWindow to create an overlapped window if the x parameter of <c>CreateWindow</c> is CW_USEDEFAULT.
		/// </para>
		/// </summary>
		public uint dwX;

		/// <summary>
		/// <para>
		/// If <c>dwFlags</c> specifies STARTF_USEPOSITION, this member is the y offset of the upper left corner of a window if a new window
		/// is created, in pixels. Otherwise, this member is ignored.
		/// </para>
		/// <para>
		/// The offset is from the upper left corner of the screen. For GUI processes, the specified position is used the first time the new
		/// process calls CreateWindow to create an overlapped window if the y parameter of <c>CreateWindow</c> is CW_USEDEFAULT.
		/// </para>
		/// </summary>
		public uint dwY;

		/// <summary>
		/// <para>
		/// If <c>dwFlags</c> specifies STARTF_USESIZE, this member is the width of the window if a new window is created, in pixels.
		/// Otherwise, this member is ignored.
		/// </para>
		/// <para>
		/// For GUI processes, this is used only the first time the new process calls CreateWindow to create an overlapped window if the
		/// nWidth parameter of <c>CreateWindow</c> is CW_USEDEFAULT.
		/// </para>
		/// </summary>
		public uint dwXSize;

		/// <summary>
		/// <para>
		/// If <c>dwFlags</c> specifies STARTF_USESIZE, this member is the height of the window if a new window is created, in pixels.
		/// Otherwise, this member is ignored.
		/// </para>
		/// <para>
		/// For GUI processes, this is used only the first time the new process calls CreateWindow to create an overlapped window if the
		/// nHeight parameter of <c>CreateWindow</c> is CW_USEDEFAULT.
		/// </para>
		/// </summary>
		public uint dwYSize;

		/// <summary>
		/// If <c>dwFlags</c> specifies STARTF_USECOUNTCHARS, if a new console window is created in a console process, this member specifies
		/// the screen buffer width, in character columns. Otherwise, this member is ignored.
		/// </summary>
		public uint dwXCountChars;

		/// <summary>
		/// If <c>dwFlags</c> specifies STARTF_USECOUNTCHARS, if a new console window is created in a console process, this member specifies
		/// the screen buffer height, in character rows. Otherwise, this member is ignored.
		/// </summary>
		public uint dwYCountChars;

		/// <summary>
		/// <para>
		/// If <c>dwFlags</c> specifies STARTF_USEFILLATTRIBUTE, this member is the initial text and background colors if a new console
		/// window is created in a console application. Otherwise, this member is ignored.
		/// </para>
		/// <para>
		/// This value can be any combination of the following values: FOREGROUND_BLUE, FOREGROUND_GREEN, FOREGROUND_RED,
		/// FOREGROUND_INTENSITY, BACKGROUND_BLUE, BACKGROUND_GREEN, BACKGROUND_RED, and BACKGROUND_INTENSITY. For example, the following
		/// combination of values produces red text on a white background:
		/// </para>
		/// <para><c>FOREGROUND_RED | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE</c></para>
		/// </summary>
		public uint dwFillAttribute; // CHARACTER_ATTRIBUTE

		/// <summary>
		/// <para>
		/// A bitfield that determines whether certain <c>STARTUPINFO</c> members are used when the process creates a window. This member can
		/// be one or more of the following values.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>STARTF_FORCEONFEEDBACK 0x00000040</term>
		/// <term>
		/// Indicates that the cursor is in feedback mode for two seconds after CreateProcess is called. The Working in Background cursor is
		/// displayed (see the Pointers tab in the Mouse control panel utility). If during those two seconds the process makes the first GUI
		/// call, the system gives five more seconds to the process. If during those five seconds the process shows a window, the system
		/// gives five more seconds to the process to finish drawing the window. The system turns the feedback cursor off after the first
		/// call to GetMessage, regardless of whether the process is drawing.
		/// </term>
		/// </item>
		/// <item>
		/// <term>STARTF_FORCEOFFFEEDBACK 0x00000080</term>
		/// <term>Indicates that the feedback cursor is forced off while the process is starting. The Normal Select cursor is displayed.</term>
		/// </item>
		/// <item>
		/// <term>STARTF_PREVENTPINNING 0x00002000</term>
		/// <term>Indicates that any windows created by the process cannot be pinned on the taskbar. This flag must be combined with STARTF_TITLEISAPPID.</term>
		/// </item>
		/// <item>
		/// <term>STARTF_RUNFULLSCREEN 0x00000020</term>
		/// <term>
		/// Indicates that the process should be run in full-screen mode, rather than in windowed mode. This flag is only valid for console
		/// applications running on an x86 computer.
		/// </term>
		/// </item>
		/// <item>
		/// <term>STARTF_TITLEISAPPID 0x00001000</term>
		/// <term>
		/// The lpTitle member contains an AppUserModelID. This identifier controls how the taskbar and Start menu present the application,
		/// and enables it to be associated with the correct shortcuts and Jump Lists. Generally, applications will use the
		/// SetCurrentProcessExplicitAppUserModelID and GetCurrentProcessExplicitAppUserModelID functions instead of setting this flag. For
		/// more information, see Application User Model IDs. If STARTF_PREVENTPINNING is used, application windows cannot be pinned on the
		/// taskbar. The use of any AppUserModelID-related window properties by the application overrides this setting for that window only.
		/// This flag cannot be used with STARTF_TITLEISLINKNAME.
		/// </term>
		/// </item>
		/// <item>
		/// <term>STARTF_TITLEISLINKNAME 0x00000800</term>
		/// <term>
		/// The lpTitle member contains the path of the shortcut file (.lnk) that the user invoked to start this process. This is typically
		/// set by the shell when a .lnk file pointing to the launched application is invoked. Most applications will not need to set this
		/// value. This flag cannot be used with STARTF_TITLEISAPPID.
		/// </term>
		/// </item>
		/// <item>
		/// <term>STARTF_UNTRUSTEDSOURCE 0x00008000</term>
		/// <term>The command line came from an untrusted source. For more information, see Remarks.</term>
		/// </item>
		/// <item>
		/// <term/>
		/// <term/>
		/// </item>
		/// <item>
		/// <term>STARTF_USECOUNTCHARS 0x00000008</term>
		/// <term>The dwXCountChars and dwYCountChars members contain additional information.</term>
		/// </item>
		/// <item>
		/// <term>STARTF_USEFILLATTRIBUTE 0x00000010</term>
		/// <term>The dwFillAttribute member contains additional information.</term>
		/// </item>
		/// <item>
		/// <term>STARTF_USEHOTKEY 0x00000200</term>
		/// <term>The hStdInput member contains additional information. This flag cannot be used with STARTF_USESTDHANDLES.</term>
		/// </item>
		/// <item>
		/// <term>STARTF_USEPOSITION 0x00000004</term>
		/// <term>The dwX and dwY members contain additional information.</term>
		/// </item>
		/// <item>
		/// <term>STARTF_USESHOWWINDOW 0x00000001</term>
		/// <term>The wShowWindow member contains additional information.</term>
		/// </item>
		/// <item>
		/// <term>STARTF_USESIZE 0x00000002</term>
		/// <term>The dwXSize and dwYSize members contain additional information.</term>
		/// </item>
		/// <item>
		/// <term>STARTF_USESTDHANDLES 0x00000100</term>
		/// <term>
		/// The hStdInput, hStdOutput, and hStdError members contain additional information. If this flag is specified when calling one of
		/// the process creation functions, the handles must be inheritable and the function's bInheritHandles parameter must be set to TRUE.
		/// For more information, see Handle Inheritance. If this flag is specified when calling the GetStartupInfo function, these members
		/// are either the handle value specified during process creation or INVALID_HANDLE_VALUE. Handles must be closed with CloseHandle
		/// when they are no longer needed. This flag cannot be used with STARTF_USEHOTKEY.
		/// </term>
		/// </item>
		/// </list>
		/// </summary>
		public STARTF dwFlags;

		/// <summary>
		/// <para>
		/// If <c>dwFlags</c> specifies STARTF_USESHOWWINDOW, this member can be any of the values that can be specified in the nCmdShow
		/// parameter for the ShowWindow function, except for SW_SHOWDEFAULT. Otherwise, this member is ignored.
		/// </para>
		/// <para>
		/// For GUI processes, the first time ShowWindow is called, its nCmdShow parameter is ignored <c>wShowWindow</c> specifies the
		/// default value. In subsequent calls to ShowWindow, the <c>wShowWindow</c> member is used if the nCmdShow parameter of
		/// <c>ShowWindow</c> is set to SW_SHOWDEFAULT.
		/// </para>
		/// </summary>
		public ushort wShowWindow;

		/// <summary>Reserved for use by the C Run-time; must be zero.</summary>
		public ushort cbReserved2;

		/// <summary>Reserved for use by the C Run-time; must be NULL.</summary>
		public IntPtr lpReserved2;

		/// <summary>
		/// <para>
		/// If <c>dwFlags</c> specifies STARTF_USESTDHANDLES, this member is the standard input handle for the process. If
		/// STARTF_USESTDHANDLES is not specified, the default for standard input is the keyboard buffer.
		/// </para>
		/// <para>
		/// If <c>dwFlags</c> specifies STARTF_USEHOTKEY, this member specifies a hotkey value that is sent as the wParam parameter of a
		/// WM_SETHOTKEY message to the first eligible top-level window created by the application that owns the process. If the window is
		/// created with the WS_POPUP window style, it is not eligible unless the WS_EX_APPWINDOW extended window style is also set. For more
		/// information, see CreateWindowEx.
		/// </para>
		/// <para>Otherwise, this member is ignored.</para>
		/// </summary>
		public HANDLE hStdInput;

		/// <summary>
		/// <para>
		/// If <c>dwFlags</c> specifies STARTF_USESTDHANDLES, this member is the standard output handle for the process. Otherwise, this
		/// member is ignored and the default for standard output is the console window's buffer.
		/// </para>
		/// <para>
		/// If a process is launched from the taskbar or jump list, the system sets <c>hStdOutput</c> to a handle to the monitor that
		/// contains the taskbar or jump list used to launch the process. For more information, see Remarks. <c>Windows 7, Windows Server
		/// 2008 R2, Windows Vista, Windows Server 2008, Windows XP and Windows Server 2003:</c> This behavior was introduced in Windows 8
		/// and Windows Server 2012.
		/// </para>
		/// </summary>
		public HANDLE hStdOutput;

		/// <summary>
		/// If <c>dwFlags</c> specifies STARTF_USESTDHANDLES, this member is the standard error handle for the process. Otherwise, this
		/// member is ignored and the default for standard error is the console window's buffer.
		/// </summary>
		public HANDLE hStdError;

		/// <summary>
		/// <para>
		/// If <c>dwFlags</c> specifies STARTF_USEFILLATTRIBUTE, this member is the initial text and background colors if a new console
		/// window is created in a console application. Otherwise, this member is ignored.
		/// </para>
		/// <para>
		/// This value can be any combination of the following values: FOREGROUND_BLUE, FOREGROUND_GREEN, FOREGROUND_RED,
		/// FOREGROUND_INTENSITY, BACKGROUND_BLUE, BACKGROUND_GREEN, BACKGROUND_RED, and BACKGROUND_INTENSITY. For example, the following
		/// combination of values produces red text on a white background:
		/// </para>
		/// <para><c>FOREGROUND_RED | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE</c></para>
		/// </summary>
		public CHARACTER_ATTRIBUTE FillAttribute { get => (CHARACTER_ATTRIBUTE)dwFillAttribute; set { dwFillAttribute = (uint)value; dwFlags = dwFlags.SetFlags(STARTF.STARTF_USEFILLATTRIBUTE, value != 0); } }

		/// <summary>
		/// <para>
		/// This member can be any of the values that can be specified in the nCmdShow parameter for the <c>ShowWindow</c> function, except
		/// for SW_SHOWDEFAULT.
		/// </para>
		/// <para>
		/// For GUI processes, the first time <c>ShowWindow</c> is called, its nCmdShow parameter is ignored <c>wShowWindow</c> specifies the
		/// default value. In subsequent calls to <c>ShowWindow</c>, the <c>wShowWindow</c> member is used if the nCmdShow parameter of
		/// <c>ShowWindow</c> is set to SW_SHOWDEFAULT.
		/// </para>
		/// </summary>
		public ShowWindowCommand ShowWindowCommand { get => (ShowWindowCommand)wShowWindow; set { wShowWindow = (ushort)value; dwFlags = dwFlags.SetFlags(STARTF.STARTF_USESHOWWINDOW, value != 0); } }

		/// <summary>
		/// <para>The x and y offset of the upper left corner of a window if a new window is created, in pixels.</para>
		/// <para>
		/// The offset is from the upper left corner of the screen. For GUI processes, the specified position is used the first time the new
		/// process calls <c>CreateWindow</c> to create an overlapped window if the x or y parameter of <c>CreateWindow</c> is CW_USEDEFAULT.
		/// </para>
		/// </summary>
		public POINT WindowPosition { get => new((int)dwX, (int)dwY); set { dwX = (uint)value.X; dwY = (uint)value.Y; dwFlags = dwFlags.SetFlags(STARTF.STARTF_USEPOSITION, value != POINT.Empty); } }

		/// <summary>
		/// <para>The height of the window if a new window is created, in pixels.</para>
		/// <para>
		/// For GUI processes, this is used only the first time the new process calls <c>CreateWindow</c> to create an overlapped window if
		/// the nHeight or nWidth parameter of <c>CreateWindow</c> is CW_USEDEFAULT.
		/// </para>
		/// </summary>
		public SIZE WindowSize { get => new((int)dwXSize, (int)dwYSize); set { dwXSize = (uint)value.cx; dwYSize = (uint)value.cy; dwFlags = dwFlags.SetFlags(STARTF.STARTF_USESIZE, value != SIZE.Empty); } }

		/// <summary>Gets the default value for this structure with the <c>cb</c> field set to the size of the structure.</summary>
		public static STARTUPINFO Default => new() { cb = (uint)Marshal.SizeOf<STARTUPINFO>() };
	}

	/// <summary>
	/// <para>
	/// Specifies the window station, desktop, standard handles, and attributes for a new process. It is used with the CreateProcess and
	/// CreateProcessAsUser functions.
	/// </para>
	/// </summary>
	/// <remarks>
	/// <para>Be sure to set the <c>cb</c> member of the STARTUPINFO structure to .</para>
	/// </remarks>
	// https://docs.microsoft.com/en-us/windows/desktop/api/winbase/ns-winbase-_startupinfoexa typedef struct _STARTUPINFOEXA { STARTUPINFOA
	// StartupInfo; LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList; } STARTUPINFOEXA, *LPSTARTUPINFOEXA;
	[PInvokeData("winbase.h", MSDNShortId = "61203f57-292d-4ea1-88f4-a3b05012d7a3")]
	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
	public struct STARTUPINFOEX
	{
		/// <summary>
		/// <para>A STARTUPINFO structure.</para>
		/// </summary>
		public STARTUPINFO StartupInfo;

		/// <summary>
		/// <para>An attribute list. This list is created by the InitializeProcThreadAttributeList function.</para>
		/// </summary>
		public IntPtr lpAttributeList;

		/// <summary>Gets the default value for this structure with the <c>cb</c> field set to the size of the structure.</summary>
		public static STARTUPINFOEX Default => new() { StartupInfo = new STARTUPINFO { cb = (uint)Marshal.SizeOf<STARTUPINFOEX>() } };
	}

	/// <summary>
	/// <para>
	/// This structure is returned by <c>GetSystemCpuSetInformation</c>. It is used to enumerate the CPU Sets on the system and determine
	/// their current state.
	/// </para>
	/// <para>
	/// This is a variable-sized structure designed for future expansion. When iterating over this structure, use the size field to determine
	/// the offset to the next structure.
	/// </para>
	/// </summary>
	// typedef struct _SYSTEM_CPU_SET_INFORMATION { DWORD Size; CPU_SET_INFORMATION_TYPE Type; union { struct { DWORD Id; WORD Group; BYTE
	// LogicalProcessorIndex; BYTE CoreIndex; BYTE LastLevelCacheIndex; BYTE NumaNodeIndex; BYTE EfficiencyClass; struct { BOOLEAN Parked :
	// 1; BOOLEAN Allocated : 1; BOOLEAN AllocatedToTargetProcess : 1; BOOLEAN RealTime : 1; BYTE ReservedFlags : 4; }; DWORD Reserved;
	// DWORD64 AllocationTag; } CpuSet; };} SYSTEM_CPU_SET_INFORMATION, *PSYSTEM_CPU_SET_INFORMATION;// https://msdn.microsoft.com/en-us/library/windows/desktop/mt186429(v=vs.85).aspx
	[PInvokeData("Winnt.h", MSDNShortId = "mt186429")]
	[StructLayout(LayoutKind.Explicit)]
	public struct SYSTEM_CPU_SET_INFORMATION
	{
		/// <summary>This is the size, in bytes, of this information structure.</summary>
		[FieldOffset(0)]
		public uint Size;

		/// <summary>This is the type of information in the structure. Applications should skip any structures with unrecognized types.</summary>
		[FieldOffset(4)]
		public CPU_SET_INFORMATION_TYPE Type;

		/// <summary>Value used when Type is CpuSetInformation.</summary>
		[FieldOffset(8)]
		public CPU_SET CpuSet;

		/// <summary>Defines values used when Type is CpuSetInformation.</summary>
		[StructLayout(LayoutKind.Sequential)]
		public struct CPU_SET
		{
			/// <summary>
			/// The ID of the specified CPU Set. This identifier can be used with SetProcessDefaultCpuSets or SetThreadSelectedCpuSets when
			/// specifying a list of CPU Sets to affinitize to.
			/// </summary>
			public uint Id;

			/// <summary>
			/// Specifies the Processor Group of the CPU Set. All other values in the CpuSet structure are relative to the processor group.
			/// </summary>
			public ushort Group;

			/// <summary>
			/// Specifies the group-relative index of the home processor of the CPU Set. Unless the CPU Set is parked for thermal or power
			/// management reasons or assigned for exclusive use to another application, threads will run on the home processor of one of
			/// their CPU Sets. The Group and LogicalProcessorIndex fields are the same as the ones found in the PROCESSOR_NUMBER structure
			/// and they correspond to the Group field and Mask field of the GROUP_AFFINITY structure.
			/// </summary>
			public byte LogicalProcessorIndex;

			/// <summary>
			/// A group-relative value indicating which "Core" has the home processor of the CPU Set. This number is the same for all CPU
			/// Sets in the same group that share significant execution resources with each other, such as different hardware threads on a
			/// single core that supports simultaneous multi-threading.
			/// </summary>
			public byte CoreIndex;

			/// <summary>
			/// A group-relative value indicating which CPU Sets share at least one level of cache with each other. This value is the same
			/// for all CPU Sets in a group that are on processors that share cache with each other.
			/// </summary>
			public byte LastLevelCacheIndex;

			/// <summary>
			/// A group-relative value indicating which NUMA node a CPU Set is on. All CPU Sets in a given group that are on the same NUMA
			/// node will have the same value for this field.
			/// </summary>
			public byte NumaNodeIndex;

			/// <summary>
			/// A value indicating the intrinsic energy efficiency of a processor for systems that support heterogeneous processors (such as
			/// ARM big.LITTLE systems). CPU Sets with higher numerical values of this field have home processors that are faster but less
			/// power-efficient than ones with lower values.
			/// </summary>
			public byte EfficiencyClass;

			/// <summary>All flags</summary>
			public SYSTEM_CPU_SET_FLAGS AllFlags;

			/// <summary>Reserved</summary>
			private readonly uint Reserved;

			/// <summary>
			/// Specifies a tag used by Core Allocation to communicate a given allocated CPU Set between threads in different components.
			/// </summary>
			public ulong AllocationTag;
		}
	}

	/// <summary>Specifies the throttling policies and how to apply them to a target thread when that thread is subject to power management.</summary>
	// typedef struct _THREAD_POWER_THROTTLING_STATE { ULONG Version; ULONG ControlMask; ULONG StateMask;} THREAD_POWER_THROTTLING_STATE,
	// *PTHREAD_POWER_THROTTLING_STATE; https://msdn.microsoft.com/en-us/library/windows/desktop/mt804325(v=vs.85).aspx
	[PInvokeData("Processthreadsapi.h", MSDNShortId = "mt804325")]
	[StructLayout(LayoutKind.Sequential)]
	public struct THREAD_POWER_THROTTLING_STATE
	{
		/// <summary/>
		public const uint THREAD_POWER_THROTTLING_CURRENT_VERSION = 1;

		/// <summary/>
		public const uint THREAD_POWER_THROTTLING_EXECUTION_SPEED = 0x1;

		/// <summary>
		/// <para>The version of the <c>THREAD_POWER_THROTTLING_STATE</c> structure.</para>
		/// <para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>THREAD_POWER_THROTTLING_CURRENT_VERSION</term>
		/// <term>The current version.</term>
		/// </item>
		/// </list>
		/// </para>
		/// </summary>
		public uint Version;

		/// <summary>
		/// <para>This field enables the caller to take control of the power throttling mechanism.</para>
		/// <para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>THREAD_POWER_THROTTLING_EXECUTION_SPEED</term>
		/// <term>Manages the execution speed of the thread.</term>
		/// </item>
		/// </list>
		/// </para>
		/// </summary>
		public uint ControlMask;

		/// <summary>
		/// <para>Manages the power throttling mechanism on/off state.</para>
		/// <para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>THREAD_POWER_THROTTLING_EXECUTION_SPEED</term>
		/// <term>Manages the execution speed of the thread.</term>
		/// </item>
		/// </list>
		/// </para>
		/// </summary>
		public uint StateMask;

		/// <summary>Creates an initialized instance of THREAD_POWER_THROTTLING_STATE.</summary>
		public static THREAD_POWER_THROTTLING_STATE Create() => new() { Version = THREAD_POWER_THROTTLING_CURRENT_VERSION, ControlMask = THREAD_POWER_THROTTLING_EXECUTION_SPEED };
	}

	/// <summary>
	/// Specifies the window station, desktop, standard handles, and appearance of the main window for a process at creation time.
	/// </summary>
	/// <remarks>
	/// <para>
	/// For graphical user interface (GUI) processes, this information affects the first window created by the CreateWindow function and
	/// shown by the ShowWindow function. For console processes, this information affects the console window if a new console is created for
	/// the process. A process can use the GetStartupInfo function to retrieve the <c>STARTUPINFO</c> structure specified when the process
	/// was created.
	/// </para>
	/// <para>
	/// If a GUI process is being started and neither STARTF_FORCEONFEEDBACK or STARTF_FORCEOFFFEEDBACK is specified, the process feedback
	/// cursor is used. A GUI process is one whose subsystem is specified as "windows."
	/// </para>
	/// <para>
	/// If a process is launched from the taskbar or jump list, the system sets <c>hStdOutput</c> to a handle to the monitor that contains
	/// the taskbar or jump list used to launch the process. To retrieve this handle, use GetStartupInfo to retrieve the <c>STARTUPINFO</c>
	/// structure and check that <c>hStdOutput</c> is set. If so, use GetMonitorInfo to check whether <c>hStdOutput</c> is a valid monitor
	/// handle (HMONITOR). The process can then use the handle to position its windows.
	/// </para>
	/// <para>
	/// If the <c>STARTF_UNTRUSTEDSOURCE</c> flag is set in the in the <c>STARTUPINFO</c> structure returned by the GetStartupInfo function,
	/// then applications should be aware that the command line is untrusted. If this flag is set, applications should disable potentially
	/// dangerous features such as macros, downloaded content, and automatic printing. This flag is optional. Applications that call
	/// CreateProcess are encouraged to set this flag when launching a program with a untrusted command line so that the created process can
	/// apply appropriate policy.
	/// </para>
	/// <para>
	/// The <c>STARTF_UNTRUSTEDSOURCE</c> flag is supported starting in Windows Vista, but it is not defined in the SDK header files prior to
	/// the Windows 10 SDK. To use the flag in versions prior to Windows 10, you can define it manually in your program.
	/// </para>
	/// <para>Examples</para>
	/// <para>For an example, see Creating Processes.</para>
	/// </remarks>
	// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-_startupinfoa typedef struct _STARTUPINFOA {
	// DWORD cb; LPSTR lpReserved; LPSTR lpDesktop; LPSTR lpTitle; DWORD dwX; DWORD dwY; DWORD dwXSize; DWORD dwYSize; DWORD dwXCountChars;
	// DWORD dwYCountChars; DWORD dwFillAttribute; DWORD dwFlags; WORD wShowWindow; WORD cbReserved2; LPBYTE lpReserved2; HANDLE hStdInput;
	// HANDLE hStdOutput; HANDLE hStdError; } STARTUPINFOA, *LPSTARTUPINFOA;
	[PInvokeData("processthreadsapi.h", MSDNShortId = "cf4b795c-52c1-4573-8328-99ee13f68bb3")]
	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
	private struct STARTUPINFO_OUT
	{
		/// <summary>The size of the structure, in bytes.</summary>
		public uint cb;

		/// <summary>Reserved; must be NULL.</summary>
		public IntPtr lpReserved;

		/// <summary>
		/// The name of the desktop, or the name of both the desktop and window station for this process. A backslash in the string indicates
		/// that the string includes both the desktop and window station names.
		/// <para>
		/// For more information, see <a href="https://msdn.microsoft.com/45016619-ed11-4b0c-84e3-f8662553c64d">Thread Connection to a Desktop</a>.
		/// </para>
		/// </summary>
		//[MarshalAs(UnmanagedType.LPTStr)]
		//public string lpDesktop;
		public StrPtrAuto lpDesktop;

		/// <summary>
		/// For console processes, this is the title displayed in the title bar if a new console window is created. If NULL, the name of the
		/// executable file is used as the window title instead. This parameter must be NULL for GUI or console processes that do not create
		/// a new console window.
		/// </summary>
		//[MarshalAs(UnmanagedType.LPTStr)]
		//public string lpTitle;
		public StrPtrAuto lpTitle;

		/// <summary>
		/// <para>
		/// If <c>dwFlags</c> specifies STARTF_USEPOSITION, this member is the x offset of the upper left corner of a window if a new window
		/// is created, in pixels. Otherwise, this member is ignored.
		/// </para>
		/// <para>
		/// The offset is from the upper left corner of the screen. For GUI processes, the specified position is used the first time the new
		/// process calls CreateWindow to create an overlapped window if the x parameter of <c>CreateWindow</c> is CW_USEDEFAULT.
		/// </para>
		/// </summary>
		public uint dwX;

		/// <summary>
		/// <para>
		/// If <c>dwFlags</c> specifies STARTF_USEPOSITION, this member is the y offset of the upper left corner of a window if a new window
		/// is created, in pixels. Otherwise, this member is ignored.
		/// </para>
		/// <para>
		/// The offset is from the upper left corner of the screen. For GUI processes, the specified position is used the first time the new
		/// process calls CreateWindow to create an overlapped window if the y parameter of <c>CreateWindow</c> is CW_USEDEFAULT.
		/// </para>
		/// </summary>
		public uint dwY;

		/// <summary>
		/// <para>
		/// If <c>dwFlags</c> specifies STARTF_USESIZE, this member is the width of the window if a new window is created, in pixels.
		/// Otherwise, this member is ignored.
		/// </para>
		/// <para>
		/// For GUI processes, this is used only the first time the new process calls CreateWindow to create an overlapped window if the
		/// nWidth parameter of <c>CreateWindow</c> is CW_USEDEFAULT.
		/// </para>
		/// </summary>
		public uint dwXSize;

		/// <summary>
		/// <para>
		/// If <c>dwFlags</c> specifies STARTF_USESIZE, this member is the height of the window if a new window is created, in pixels.
		/// Otherwise, this member is ignored.
		/// </para>
		/// <para>
		/// For GUI processes, this is used only the first time the new process calls CreateWindow to create an overlapped window if the
		/// nHeight parameter of <c>CreateWindow</c> is CW_USEDEFAULT.
		/// </para>
		/// </summary>
		public uint dwYSize;

		/// <summary>
		/// If <c>dwFlags</c> specifies STARTF_USECOUNTCHARS, if a new console window is created in a console process, this member specifies
		/// the screen buffer width, in character columns. Otherwise, this member is ignored.
		/// </summary>
		public uint dwXCountChars;

		/// <summary>
		/// If <c>dwFlags</c> specifies STARTF_USECOUNTCHARS, if a new console window is created in a console process, this member specifies
		/// the screen buffer height, in character rows. Otherwise, this member is ignored.
		/// </summary>
		public uint dwYCountChars;

		/// <summary>
		/// <para>
		/// If <c>dwFlags</c> specifies STARTF_USEFILLATTRIBUTE, this member is the initial text and background colors if a new console
		/// window is created in a console application. Otherwise, this member is ignored.
		/// </para>
		/// <para>
		/// This value can be any combination of the following values: FOREGROUND_BLUE, FOREGROUND_GREEN, FOREGROUND_RED,
		/// FOREGROUND_INTENSITY, BACKGROUND_BLUE, BACKGROUND_GREEN, BACKGROUND_RED, and BACKGROUND_INTENSITY. For example, the following
		/// combination of values produces red text on a white background:
		/// </para>
		/// <para><c>FOREGROUND_RED | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE</c></para>
		/// </summary>
		public uint dwFillAttribute; // CHARACTER_ATTRIBUTE

		/// <summary>
		/// <para>
		/// A bitfield that determines whether certain <c>STARTUPINFO</c> members are used when the process creates a window. This member can
		/// be one or more of the following values.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>STARTF_FORCEONFEEDBACK 0x00000040</term>
		/// <term>
		/// Indicates that the cursor is in feedback mode for two seconds after CreateProcess is called. The Working in Background cursor is
		/// displayed (see the Pointers tab in the Mouse control panel utility). If during those two seconds the process makes the first GUI
		/// call, the system gives five more seconds to the process. If during those five seconds the process shows a window, the system
		/// gives five more seconds to the process to finish drawing the window. The system turns the feedback cursor off after the first
		/// call to GetMessage, regardless of whether the process is drawing.
		/// </term>
		/// </item>
		/// <item>
		/// <term>STARTF_FORCEOFFFEEDBACK 0x00000080</term>
		/// <term>Indicates that the feedback cursor is forced off while the process is starting. The Normal Select cursor is displayed.</term>
		/// </item>
		/// <item>
		/// <term>STARTF_PREVENTPINNING 0x00002000</term>
		/// <term>Indicates that any windows created by the process cannot be pinned on the taskbar. This flag must be combined with STARTF_TITLEISAPPID.</term>
		/// </item>
		/// <item>
		/// <term>STARTF_RUNFULLSCREEN 0x00000020</term>
		/// <term>
		/// Indicates that the process should be run in full-screen mode, rather than in windowed mode. This flag is only valid for console
		/// applications running on an x86 computer.
		/// </term>
		/// </item>
		/// <item>
		/// <term>STARTF_TITLEISAPPID 0x00001000</term>
		/// <term>
		/// The lpTitle member contains an AppUserModelID. This identifier controls how the taskbar and Start menu present the application,
		/// and enables it to be associated with the correct shortcuts and Jump Lists. Generally, applications will use the
		/// SetCurrentProcessExplicitAppUserModelID and GetCurrentProcessExplicitAppUserModelID functions instead of setting this flag. For
		/// more information, see Application User Model IDs. If STARTF_PREVENTPINNING is used, application windows cannot be pinned on the
		/// taskbar. The use of any AppUserModelID-related window properties by the application overrides this setting for that window only.
		/// This flag cannot be used with STARTF_TITLEISLINKNAME.
		/// </term>
		/// </item>
		/// <item>
		/// <term>STARTF_TITLEISLINKNAME 0x00000800</term>
		/// <term>
		/// The lpTitle member contains the path of the shortcut file (.lnk) that the user invoked to start this process. This is typically
		/// set by the shell when a .lnk file pointing to the launched application is invoked. Most applications will not need to set this
		/// value. This flag cannot be used with STARTF_TITLEISAPPID.
		/// </term>
		/// </item>
		/// <item>
		/// <term>STARTF_UNTRUSTEDSOURCE 0x00008000</term>
		/// <term>The command line came from an untrusted source. For more information, see Remarks.</term>
		/// </item>
		/// <item>
		/// <term/>
		/// <term/>
		/// </item>
		/// <item>
		/// <term>STARTF_USECOUNTCHARS 0x00000008</term>
		/// <term>The dwXCountChars and dwYCountChars members contain additional information.</term>
		/// </item>
		/// <item>
		/// <term>STARTF_USEFILLATTRIBUTE 0x00000010</term>
		/// <term>The dwFillAttribute member contains additional information.</term>
		/// </item>
		/// <item>
		/// <term>STARTF_USEHOTKEY 0x00000200</term>
		/// <term>The hStdInput member contains additional information. This flag cannot be used with STARTF_USESTDHANDLES.</term>
		/// </item>
		/// <item>
		/// <term>STARTF_USEPOSITION 0x00000004</term>
		/// <term>The dwX and dwY members contain additional information.</term>
		/// </item>
		/// <item>
		/// <term>STARTF_USESHOWWINDOW 0x00000001</term>
		/// <term>The wShowWindow member contains additional information.</term>
		/// </item>
		/// <item>
		/// <term>STARTF_USESIZE 0x00000002</term>
		/// <term>The dwXSize and dwYSize members contain additional information.</term>
		/// </item>
		/// <item>
		/// <term>STARTF_USESTDHANDLES 0x00000100</term>
		/// <term>
		/// The hStdInput, hStdOutput, and hStdError members contain additional information. If this flag is specified when calling one of
		/// the process creation functions, the handles must be inheritable and the function's bInheritHandles parameter must be set to TRUE.
		/// For more information, see Handle Inheritance. If this flag is specified when calling the GetStartupInfo function, these members
		/// are either the handle value specified during process creation or INVALID_HANDLE_VALUE. Handles must be closed with CloseHandle
		/// when they are no longer needed. This flag cannot be used with STARTF_USEHOTKEY.
		/// </term>
		/// </item>
		/// </list>
		/// </summary>
		public STARTF dwFlags;

		/// <summary>
		/// <para>
		/// If <c>dwFlags</c> specifies STARTF_USESHOWWINDOW, this member can be any of the values that can be specified in the nCmdShow
		/// parameter for the ShowWindow function, except for SW_SHOWDEFAULT. Otherwise, this member is ignored.
		/// </para>
		/// <para>
		/// For GUI processes, the first time ShowWindow is called, its nCmdShow parameter is ignored <c>wShowWindow</c> specifies the
		/// default value. In subsequent calls to ShowWindow, the <c>wShowWindow</c> member is used if the nCmdShow parameter of
		/// <c>ShowWindow</c> is set to SW_SHOWDEFAULT.
		/// </para>
		/// </summary>
		public ushort wShowWindow;

		/// <summary>Reserved for use by the C Run-time; must be zero.</summary>
		public ushort cbReserved2;

		/// <summary>Reserved for use by the C Run-time; must be NULL.</summary>
		public IntPtr lpReserved2;

		/// <summary>
		/// <para>
		/// If <c>dwFlags</c> specifies STARTF_USESTDHANDLES, this member is the standard input handle for the process. If
		/// STARTF_USESTDHANDLES is not specified, the default for standard input is the keyboard buffer.
		/// </para>
		/// <para>
		/// If <c>dwFlags</c> specifies STARTF_USEHOTKEY, this member specifies a hotkey value that is sent as the wParam parameter of a
		/// WM_SETHOTKEY message to the first eligible top-level window created by the application that owns the process. If the window is
		/// created with the WS_POPUP window style, it is not eligible unless the WS_EX_APPWINDOW extended window style is also set. For more
		/// information, see CreateWindowEx.
		/// </para>
		/// <para>Otherwise, this member is ignored.</para>
		/// </summary>
		public HANDLE hStdInput;

		/// <summary>
		/// <para>
		/// If <c>dwFlags</c> specifies STARTF_USESTDHANDLES, this member is the standard output handle for the process. Otherwise, this
		/// member is ignored and the default for standard output is the console window's buffer.
		/// </para>
		/// <para>
		/// If a process is launched from the taskbar or jump list, the system sets <c>hStdOutput</c> to a handle to the monitor that
		/// contains the taskbar or jump list used to launch the process. For more information, see Remarks. <c>Windows 7, Windows Server
		/// 2008 R2, Windows Vista, Windows Server 2008, Windows XP and Windows Server 2003:</c> This behavior was introduced in Windows 8
		/// and Windows Server 2012.
		/// </para>
		/// </summary>
		public HANDLE hStdOutput;

		/// <summary>
		/// If <c>dwFlags</c> specifies STARTF_USESTDHANDLES, this member is the standard error handle for the process. Otherwise, this
		/// member is ignored and the default for standard error is the console window's buffer.
		/// </summary>
		public HANDLE hStdError;

		/// <summary>Performs an implicit conversion from <see cref="STARTUPINFO_OUT"/> to <see cref="STARTUPINFO"/>.</summary>
		/// <param name="sio">The STARTUPINFO_OUT instance.</param>
		/// <returns>The result of the conversion.</returns>
		public static implicit operator STARTUPINFO(STARTUPINFO_OUT sio) => new()
		{
			cb = sio.cb,
			lpReserved = sio.lpReserved,
			lpDesktop = sio.lpDesktop,
			lpTitle = sio.lpTitle,
			dwX = sio.dwX,
			dwY = sio.dwY,
			dwXSize = sio.dwXSize,
			dwYSize = sio.dwYSize,
			dwXCountChars = sio.dwXCountChars,
			dwYCountChars = sio.dwYCountChars,
			dwFillAttribute = sio.dwFillAttribute,
			dwFlags = sio.dwFlags,
			wShowWindow = sio.wShowWindow,
			cbReserved2 = sio.cbReserved2,
			lpReserved2 = sio.lpReserved2,
			hStdInput = sio.hStdInput,
			hStdOutput = sio.hStdOutput,
			hStdError = sio.hStdError,
		};
	}

	/// <summary>Provides a <see cref="SafeHandle"/> to a process that releases a created HPROCESS instance at disposal using CloseHandle.</summary>
	[AutoSafeHandle(null, typeof(HPROCESS), typeof(SafeSyncHandle))]
	[AdjustAutoMethodNamePattern(@"Process|Ex\b", "")]
	public partial class SafeHPROCESS
	{
		/// <summary>Gets a handle to the current process that can be used across processes.</summary>
		/// <value>The current process handle.</value>
		public static SafeHPROCESS Current => new(GetCurrentProcess().Duplicate());
	}

	/// <summary>Provides a <see cref="SafeHandle"/> to a thread that releases a created HTHREAD instance at disposal using CloseHandle.</summary>
	[AutoSafeHandle(null, typeof(HTHREAD), typeof(SafeSyncHandle))]
	[AdjustAutoMethodNamePattern(@"Thread|Ex\b", "")]
	public partial class SafeHTHREAD
	{
		/// <summary>
		/// <para>Creates a thread to execute within the virtual address space of the calling process.</para>
		/// <para>To create a thread that runs in the virtual address space of another process, use the <c>CreateRemoteThread</c> function.</para>
		/// </summary>
		/// <param name="lpStartAddress">
		/// A pointer to the application-defined function to be executed by the thread. This pointer represents the starting address of the
		/// thread. For more information on the thread function, see <c>ThreadProc</c>.
		/// </param>
		/// <param name="lpParameter">A pointer to a variable to be passed to the thread.</param>
		/// <param name="lpThreadId">
		/// A pointer to a variable that receives the thread identifier. If this parameter is <c>NULL</c>, the thread identifier is not returned.
		/// </param>
		/// <param name="dwCreationFlags">
		/// <para>The flags that control the creation of the thread.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>0</term>
		/// <term>The thread runs immediately after creation.</term>
		/// </item>
		/// <item>
		/// <term>CREATE_SUSPENDED 0x00000004</term>
		/// <term>The thread is created in a suspended state, and does not run until the ResumeThread function is called.</term>
		/// </item>
		/// <item>
		/// <term>STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000</term>
		/// <term>
		/// The dwStackSize parameter specifies the initial reserve size of the stack. If this flag is not specified, dwStackSize specifies
		/// the commit size.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="dwStackSize">
		/// The initial size of the stack, in bytes. The system rounds this value to the nearest page. If this parameter is zero, the new
		/// thread uses the default size for the executable. For more information, see Thread Stack Size.
		/// </param>
		/// <param name="lpThreadAttributes">
		/// <para>
		/// A pointer to a <c>SECURITY_ATTRIBUTES</c> structure that determines whether the returned handle can be inherited by child
		/// processes. If lpThreadAttributes is NULL, the handle cannot be inherited.
		/// </para>
		/// <para>
		/// The <c>lpSecurityDescriptor</c> member of the structure specifies a security descriptor for the new thread. If lpThreadAttributes
		/// is NULL, the thread gets a default security descriptor. The ACLs in the default security descriptor for a thread come from the
		/// primary token of the creator.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is a handle to the new thread.</para>
		/// <para>If the function fails, the return value is <c>NULL</c>. To get extended error information, call <c>GetLastError</c>.</para>
		/// <para>
		/// Note that <c>CreateThread</c> may succeed even if lpStartAddress points to data, code, or is not accessible. If the start address
		/// is invalid when the thread runs, an exception occurs, and the thread terminates. Thread termination due to a invalid start
		/// address is handled as an error exit for the thread's process. This behavior is similar to the asynchronous nature of
		/// <c>CreateProcess</c>, where the process is created even if it refers to invalid or missing dynamic-link libraries (DLLs).
		/// </para>
		/// </returns>
		public static SafeHTHREAD Create(ThreadProc lpStartAddress, [In, Optional] IntPtr lpParameter, out uint lpThreadId, [Optional] CREATE_THREAD_FLAGS dwCreationFlags, [Optional] SizeT dwStackSize, [In, Optional] SECURITY_ATTRIBUTES? lpThreadAttributes) =>
			Kernel32.CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, out lpThreadId);

		/// <summary>
		/// <para>Creates a thread to execute within the virtual address space of the calling process.</para>
		/// <para>To create a thread that runs in the virtual address space of another process, use the <c>CreateRemoteThread</c> function.</para>
		/// </summary>
		/// <param name="lpStartAddress">A pointer to the application-defined function to be executed by the thread. This pointer represents the starting address of the
		/// thread. For more information on the thread function, see <c>ThreadProc</c>.</param>
		/// <returns>
		/// <para>If the function succeeds, the return value is a handle to the new thread.</para>
		/// <para>If the function fails, the return value is <c>NULL</c>. To get extended error information, call <c>GetLastError</c>.</para>
		/// <para>
		/// Note that <c>CreateThread</c> may succeed even if lpStartAddress points to data, code, or is not accessible. If the start address
		/// is invalid when the thread runs, an exception occurs, and the thread terminates. Thread termination due to a invalid start
		/// address is handled as an error exit for the thread's process. This behavior is similar to the asynchronous nature of
		/// <c>CreateProcess</c>, where the process is created even if it refers to invalid or missing dynamic-link libraries (DLLs).
		/// </para>
		/// </returns>
		public static SafeHTHREAD Create(ThreadProc lpStartAddress) => Create(lpStartAddress, IntPtr.Zero, out _);

		/// <summary>Gets a handle to the current thread that can be used across processes.</summary>
		/// <value>The current thread handle.</value>
		public static SafeHTHREAD Current => new(GetCurrentThread().Duplicate());
	}

	/// <summary>
	/// Contains information about a newly created process and its primary thread. It is used with the <c>CreateProcess</c>,
	/// <c>CreateProcessAsUser</c>, <c>CreateProcessWithLogonW</c>, or <c>CreateProcessWithTokenW</c> function. This class will close the
	/// process and thread handles at disposal.
	/// </summary>
	// typedef struct _PROCESS_INFORMATION { HANDLE hProcess; HANDLE hThread; DWORD dwProcessId; DWORD dwThreadId;} PROCESS_INFORMATION,
	// *LPPROCESS_INFORMATION; https://msdn.microsoft.com/en-us/library/windows/desktop/ms684873(v=vs.85).aspx
	[PInvokeData("WinBase.h", MSDNShortId = "ms684873")]
	public sealed class SafePROCESS_INFORMATION : IDisposable
	{
		/// <summary>Initializes a new instance of the <see cref="SafePROCESS_INFORMATION"/> class.</summary>
		/// <param name="pi">The pi.</param>
		public SafePROCESS_INFORMATION(in PROCESS_INFORMATION pi)
		{
			hProcess = new SafeHPROCESS((IntPtr)pi.hProcess);
			hThread = new SafeHTHREAD((IntPtr)pi.hThread);
			dwProcessId = pi.dwProcessId;
			dwThreadId = pi.dwThreadId;
		}

		/// <summary>Initializes an empty instance of the <see cref="SafePROCESS_INFORMATION"/> class.</summary>
		public SafePROCESS_INFORMATION()
		{
			hProcess = new SafeHPROCESS(IntPtr.Zero);
			hThread = new SafeHTHREAD(IntPtr.Zero);
		}

		/// <summary>
		/// A value that can be used to identify a process. The value is valid from the time the process is created until all handles to the
		/// process are closed and the process object is freed; at this point, the identifier may be reused.
		/// </summary>
		public uint dwProcessId { get; }

		/// <summary>
		/// A value that can be used to identify a thread. The value is valid from the time the thread is created until all handles to the
		/// thread are closed and the thread object is freed; at this point, the identifier may be reused.
		/// </summary>
		public uint dwThreadId { get; }

		/// <summary>
		/// A handle to the newly created process. The handle is used to specify the process in all functions that perform operations on the
		/// process object.
		/// </summary>
		public SafeHPROCESS hProcess { get; private set; }

		/// <summary>
		/// A handle to the primary thread of the newly created process. The handle is used to specify the thread in all functions that
		/// perform operations on the thread object.
		/// </summary>
		public SafeHTHREAD hThread { get; private set; }

		/// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
		void IDisposable.Dispose()
		{
			hProcess.Dispose();
			hThread.Dispose();
		}
	}

	/// <summary>
	/// Provides a <see cref="SafeHandle"/> for a list of <see cref="PROC_THREAD_ATTRIBUTE"/> structures that is disposed using <see cref="DeleteProcThreadAttributeList"/>.
	/// </summary>
	public class SafeProcThreadAttributeList : SafeHANDLE
	{
		private readonly List<(PROC_THREAD_ATTRIBUTE attr, object obj, PinnedObject ptr)> values = [];

		/// <summary>Initializes a new instance of the <see cref="SafeProcThreadAttributeList"/> class and assigns an existing handle.</summary>
		/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
		/// <param name="ownsHandle">
		/// <see langword="true"/> to reliably release the handle during the finalization phase; otherwise, <see langword="false"/> (not recommended).
		/// </param>
		public SafeProcThreadAttributeList(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { }

		/// <summary>Initializes a new instance of the <see cref="SafeProcThreadAttributeList"/> class.</summary>
		private SafeProcThreadAttributeList() : base() { }

		/// <summary>Creates an instance of a SafeProcThreadAttributeList with a single attribute and value added.</summary>
		/// <param name="attribute">The attribute.</param>
		/// <param name="value">The value.</param>
		/// <returns>A <see cref="SafeProcThreadAttributeList"/> instance with the attribute/value pair added.</returns>
		public static SafeProcThreadAttributeList Create(PROC_THREAD_ATTRIBUTE attribute, object value) =>
			Create(new Dictionary<PROC_THREAD_ATTRIBUTE, object> { { attribute, value } });

		/// <summary>Creates an instance of a SafeProcThreadAttributeList with a list of attributes/value pairs added.</summary>
		/// <param name="attributes">A dictionary of attribute/value pairs to add.</param>
		/// <returns>A <see cref="SafeProcThreadAttributeList"/> instance with the supplied attribute/value pairs added.</returns>
		public static SafeProcThreadAttributeList Create(IDictionary<PROC_THREAD_ATTRIBUTE, object> attributes)
		{
			if (attributes is null) throw new ArgumentNullException(nameof(attributes));
			foreach (KeyValuePair<PROC_THREAD_ATTRIBUTE, object> kv in attributes)
				if (!IsValid(kv.Key, kv.Value)) throw new ArgumentException($"The attribute {kv.Key} does not support a value of type {kv.Value.GetType().Name}.");

			SizeT sz = 0;
			InitializeProcThreadAttributeList(IntPtr.Zero, (uint)attributes.Count, 0, ref sz);
			if (sz == 0) Win32Error.ThrowLastError();
			RuntimeHelpers.PrepareConstrainedRegions();
			IntPtr ptr = Marshal.AllocHGlobal(sz);
			if (!InitializeProcThreadAttributeList(ptr, (uint)attributes.Count, 0, ref sz))
			{
				Marshal.FreeHGlobal(ptr);
				Win32Error.ThrowLastError();
			}

			SafeProcThreadAttributeList hAttr = new(ptr);
			foreach (KeyValuePair<PROC_THREAD_ATTRIBUTE, object> kv in attributes)
				hAttr.Add(kv.Key, kv.Value);
			return hAttr;
		}

		/// <summary>Clones this instance.</summary>
		/// <returns>A new instance of the list with all attributes and objects duplicated.</returns>
		public SafeProcThreadAttributeList Clone()
		{
			Dictionary<PROC_THREAD_ATTRIBUTE, object> d = [];
			foreach ((PROC_THREAD_ATTRIBUTE attr, object obj, _) in values) d.Add(attr, obj);
			return Create(d);
		}

		/// <inheritdoc/>
		protected override bool InternalReleaseHandle()
		{
			foreach ((PROC_THREAD_ATTRIBUTE _, object _, PinnedObject ptr) in values)
				ptr.Dispose();
			values.Clear();
			DeleteProcThreadAttributeList(handle);
			Marshal.FreeHGlobal(handle);
			return true;
		}

		private static bool IsValid(PROC_THREAD_ATTRIBUTE attr, object value) => value is not null && value.GetType().Equals(attr.ValidType);

		private void Add(PROC_THREAD_ATTRIBUTE attr, object value)
		{
			PinnedObject pVal = new(value);
			values.Add((attr, value, pVal));
			if (!UpdateProcThreadAttribute(handle, 0, attr, pVal, InteropExtensions.SizeOf(value)))
				Win32Error.ThrowLastError();
		}
	}
}